Le langage SMS est exclu sur les forums ProgBoards, tout message ne respectant pas la charte sera déplacé, modifié, ou supprimé par nos modérateurs.

Forum Informatique » Algorithmes » générer une carte au hasard

Bubonik
ProgBoarder
Citer - Posté le 03/06/2005 à 21:30
Bonjour. J'ai fait un programme qui affiche une carte (pas routière, plutôt style jeu vidéo) à l'écran, dans laquelle on peut se déplacer.
Les caractéristiques : la carte est composée de tuiles (textures). Pour le moment, je n'ai que deux textures : herbe et mer.
À chaque paire de textures sont associées 14 ou 12 (je n'ai pas encore fait mon choix) tuiles qui font les limites entre les deux textures : je divise les tuiles :
soit la tuile divisée en
-A le coin Haut Gauche
-B le coin Haut Droit
-C le coin Bas Gauche
-D le coin Bas Droit
et je peux remplir A, B, C ou D avec de l'herbe ou de la mer.
J'ai donc 16 possibilités de tuiles par paire, sauf que comme j'ai déjà mes tuiles avec uniquement de l'herbe ou uniquement de la mer, je ne les mets pas et ça me fait donc 14 tuiles.

La carte est représntée par un tableau d'entiers à deux dimensions de taille variable (par exemple 50*50).
Chaque tuile étant représentée par un numéro, je voudrais générer au hasard une carte cohérente (c'est-à-dire que je ne veux pas avoir une texture 'herbe' directement à côté d'une 'mer' mais avoir au contraire :
'herbe' puis 'limite avec A C herbe et B D mer', ce qui me permetd'avoir non pas des côtes carrées, mais au contraire de belles îles aux formes variées et aux contours d'apparence irrégulière.

Voilà. Je pensais donc repérer précisément les tuiles en leur attribuant un numéro choisi en fonction des bits (par exemple, le premier bit signifierait que le carré A de la tuile est rempli de la texture principale de la paire, etc. pour les 4 premiers et les autres pour distinguer la paire de textures en question, mais ça ne va pas bien)...

J'attends avec impatience des propositions !

[edit] Pas de raison pour un titre en gras [/edit]

Edité par neliger (13/06/2005 05:59:21)
Fser
Code-Libre.org
RemonterCiter - Posté le 04/06/2005 à 11:28
Reponse comme ça au hasard ( je n'ai jamais généré de carte aléatoirement, mais j'en ai déjà affiché )
le principe serait de creer une boucle imbriquée dans une autre boucle, et de tester la parité de l'iteration pour savoir ce que tu affiche comme texture.
bon en fait ça serait pas tres aléatoire, je le consoit ...
mais je relierai le poste apres.

donc voilà le pseudo bout de code
( je sais tres mal ecrire en algo (langue) )


creer deux nombres entiers i et j, nuls.
tant que i < hauteur_carte
tant que j < largeur_carte
si i et j ont la meme parité, afficher une texture
sinon afficher une autre texture
fin tant que
fin tant que.



j'ai fait ça rapidement, je pense qu'il y a moyen de continuer dans cette voie, meme si elle n'est pas géniale ...
en multipliant les conditions, tu pourrai generer un nombre associé a une texture toussa.

edit : je crois que c'est pas ça du tout que tu veux (héhé
mais je laisse quand meme des fois que ça en inspire d'autres

Edité par Fser (04/06/2005 11:29:19)
``Montre-moi ton code, dissimule tes structures de données, je continuerai à être mystifié. Montre-moi tes structures de données et je n'aurai sans doute pas besoin de voir ton code, il me semblera évident.''
SoløzerK
Modérateur
RemonterCiter - Posté le 04/06/2005 à 16:42
Bubonik > ton premier probleme, ça va déjà être de générer l'emplacement des tuiles d'herbe et de mer, sans encore te soucier de leurs contours, pour faire en sorte que tu ais de vastes étendues de mer et de terre, et pas un bordel comme : une case de terre, deux de mer, une de terre, une de mer, etc... qui ne correspondrait pas du tout à un paysage "naturel". Personnellement, voila comment je commencerai par faire :

1. Partir au tout début d'une case au hasard de l'écran (une case=un emplacement pour une tuile, quoi).
2. Attribuer de l'herbe ou de la mer à cette case.
3. Partir dans toutes les directions à partir de cette case.
4. Puis, pour chaque case ainsi atteinte, choisir au hasard mer ou herbe, MAIS avec une chance beaucoup plus importante de choisir la meme tuile que la case d'où on est venu pour atteindre la case courante.
5 . Retourner à l'étape 3, mais cette fois à partir de la case courante.

Et ainsi de suite jusqu'à avoir recouvert tout l'écran, ou toute la surface de la carte si elle est plus grande que l'écran. Le résultat final sera que tu auras de temps en temps un changement de tuile, mais rarement, et que chaque fois qu'un changement de tuile se produira, il entrainera la formation d'une grande surface de cette meme tuile. En gros, on aura bien de grandes surfaces homogènes. Mettons par exemple que la chance de choisir la meme tuile à l'étape 4 soit nommée alpha. Alors, alpha sera un des parametres du générateur de cartes : plus alpha est grand, plus il est difficile de changer de tuile en cours de route et donc moins la carte contiendra de surfaces homogenes différentes. Si alpha est petit, en revanche, tu te retrouvera avec de petites surfaces herbes et mer alternées. Je te conseille donc de tester différentes valeurs pour alpha pour trouver celle qui te parait la plus convenable pour ce que tu veux.
Bien sûr, il ne s'agit là que d'un algo de départ, tu dois pouvoir l'améliorer ensuite (peut etre que tu préfereras avoir systématiquement de l'herbe au tout début, ou encore forcément de la mer aux bords de l'écran, ou encore faire en sorte d'avoir un alpha différent pour la mer et pour la terre, etc...), mais l'essentiel y est.
Bon je vais goûter ^^
à mon retour je posterai une autre réponse avec un exemple d'implémenation de ça, et aussi une autre réponse pour les contours des tuiles, une fois la map générée.
"Soyez un homme, Maître Ridley. Nous allons en ce jour, par la grâce de Dieu, allumer en Angleterre une chandelle qui, je le tiens pour certain, ne s'éteindra jamais."
---
http://www.sekren.org
SoløzerK
Modérateur
RemonterCiter - Posté le 04/06/2005 à 18:36
je continue (sourire)
Pour l'implémentation, je pense que le mieux est de faire une fonction récursive (si tu ne connais pas la récursivité, je te conseille de te référer aux urls du sujet épinglé de ce forum). En supposant que alea() est une fonction renvoyant un nombre aléatoire entre 0 et 100, pour une carte en 30*30, ça donnerait quelque chose comme ça (C++) :

int map[30][30]={ false }; // La carte du terrain : si un élément vaut 0, c'est de l'herbe, sinon de la mer
bool is_generated_map[30][30]={ false }; // Ce tableau permet de savoir quelles cases ont déjà été générées, pour ne pas repasser dessus.
int alpha=90; // Alpha : 90% de chances de garder la même tuile.
int decalage[8][2]={ {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1} };

void generate_map(int y, int x, int tuile_precedente)
{
if((y>29) || (y<0) || (x>29) || (x<0))
return;

int tuile;
if(alea()<=alpha)
{
tuile=tuile_precedente;
map[y][x]=tuile_precedente;
}
else
{
if(tuile_precedente==0)
{
tuile=1;
map[y][x]=1;
}
else
{
tuile=0;
map[y][x]=0;
}
}
is_generated_map[y][x]=true;

for(int dec=0; dec<8; ++dec)
{
if(!is_generated_map[y+decalage[dec][0]][x+decalage[dec][1]])
generate_map(y+decalage[dec][0], x+decalage[dec][1], tuile);
}
}



Le tableau decalage sert a passer à toutes les cases autour de la case courante (en haut à gauche, en haut, en haut à droite, etc...).
On aurait aussi pu remplacer le bloc de if en haut par un tuile=!tuile_precedente dans le cas où on change de tuile, puisqu'on utilise les valeurs 0 et 1 pour les tuiles et que 0=!1 et vice-versa, mais j'ai préféré ne pas trop complexifier le code.
Pour lancer la génération, il suffit d'appeler generate_map avec y et x comme coordonnées de la case de départ et tuile_precedente la tuile de départ (celle dont je parlais dans l'étape 1).
J'ai testé en codant ça vite fait la génération de maps en 30*30, en commençant invariablement à la position (15;15), avec de l'herbe comme tuile de départ. Si tu veux le code source du programme, c'est là :

http://membres.lycos.fr/sekren/generate/generate.cpp

Exemples de cartes générées (~ = mer, O = herbe) :

http://membres.lycos.fr/sekren/generate/map_98.txt << alpha=98%
http://membres.lycos.fr/sekren/generate/map_90.txt << alpha=90%
http://membres.lycos.fr/sekren/generate/map_50.txt << alpha=50%, pourri sauf pour un marais, éventuellement (sourire)

On remarque tout de suite qu'il y a un probleme : les cartes générées présentent des "bras" de terre ou de mer, de longues lignes en diagonale. La raison en est trés simple : l'algorithme utilisé est un DFS, Depth First Search, une recherche en profondeur. Cela signifie qu'il va "persister" dans une direction, puis dans une autre, etc... (pour faire simple), justement parce qu'il procède en profondeur. C'est tout à fait problématique, ici, et j'aurai dû y penser en proposant l'algo au dessus. Mais la solution est simple : il suffit de remplacer le parcours en profondeur par un parcours en largeur, qui lui va procéder dans toutes les direction à la fois, en même temps. Avec la même façon de procéder mais en utilisant un parcours en largeur, tu obtiendras des cartes vraiment bien pour un alpha tournant dans les 90 à 100%. Si tu as besoin d'informations pour le parcours en largeur, je te suggere de jeter un oeil aux tutos du sujet épinglé de ce forum et d'utiliser google (sourire) De toute façon, je pense que je vais essayer d'implémenter ça pour voir ce que ça donne, et donc je posterai une réponse avec le code correspondant ici.
"Soyez un homme, Maître Ridley. Nous allons en ce jour, par la grâce de Dieu, allumer en Angleterre une chandelle qui, je le tiens pour certain, ne s'éteindra jamais."
---
http://www.sekren.org
Fser
Code-Libre.org
RemonterCiter - Posté le 04/06/2005 à 18:48
tu fais chier, je me sent trop ringard a coté de ça (héhé
``Montre-moi ton code, dissimule tes structures de données, je continuerai à être mystifié. Montre-moi tes structures de données et je n'aurai sans doute pas besoin de voir ton code, il me semblera évident.''
Bubonik
ProgBoarder
RemonterCiter - Posté le 05/06/2005 à 00:50
Bon, le problème semble en très bonne voie ! (héhé
Poly Progr@ms
Guest Star
RemonterCiter - Posté le 12/06/2005 à 17:51
MDR SoloZerK, ca c'est de l'aide de pro. T'as eu le droit à un tuto en direct Bubonik (sourire).
Bubonik
ProgBoarder
RemonterCiter - Posté le 12/06/2005 à 22:09
Bah, on finit par être blasé : l'aide de SoløzerK est toujours d'une qualité similaire... (héhé
Bon, j'ai plus qu'à dérécursiver cet algo et ce sera parfait (en attendant, j'ai réglé de petits détails dans le programme lui-même).
Allez, je vais quand même dire merci à Solø mais y a vraiment pas de quoi, c'est juste un petit lèche-botte (clein d'oeil)

P.S. Poly : même problème que Solø : on finit par être blasé de la qualité de tes sites (je viens de voir ton blog), c'est énervant : si tu veux nous surprendre, fais nous plutôt un truc pourri ! (héhé

Edité par Bubonik (12/06/2005 22:12:32)

Poster une réponse

STOP aux fautes volontaires !
Message
Formatage
Note: pour partager du code source, merci d'utiliser le wall !
Smileys (sourire) (yekyek) (clein d'oeil) (désapprouve) (triste) (cool) (langue) (confus) (gêné) (neutre) (eek) (surpris) (diable) (flèche) (exclamation) (question) (diable) (idée) (méchant)
Pseudonyme
Recopiez le code
v6 © Computaid SPRL 2005-2008 - Tous droits réservés - Hébergé par eTigris - Page générée en 0,103 s - Crédits - Stats
1 connecté