Sélectionner les cases cotières d'une carte - Version imprimable +- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org) +-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38) +--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51) +--- Sujet : Sélectionner les cases cotières d'une carte (/showthread.php?tid=5199) Pages :
1
2
|
Sélectionner les cases cotières d'une carte - Xenos - 06-03-2014 Salut à tous! J'ouvre tellement peu les sujets que je n'ai même pas le réflexe de poster ici quand j'ai un problème >.> J'ai une table MySQL contenant les cases de la carte du jeu, structurée comme ceci: Citation :x INT SIGNED Je cherche à sélectionner toutes les cases côtières de la carte, d'altitude négative ou nulle. Donc, je cherche toutes les cases (x,y) telles que mer=0 (case terrestre) et altitude<=0 (sous le niveau de la mer), et telles que l'une de ses voisines (x-1,y-1) ou (x-1,y+1) ou (x+1,y-1) ou (x+1,y+1) soit maritime (mer=1). Le but est de pouvoir inonder ces cases côtières dont l'altitude est négative (logique: une case terrestre voisine de la mer et en-dessous de celle-ci ne reste pas terrestre très longtemps!): la sélection SELECT sera transformée en un UPDATE. Pour l'instant, j'ai cette requête:
Où je sélectionne les données de la case cotière (case0), ainsi que celles de la case maritime voisine (case1). La requête s'exécute en 10secondes. Auriez-vous une requête plus véloce, sachant que la table des cases contient 516k cases actuellement (ce nombre ne changera pas)? RE: Sélectionner les cases cotières d'une carte - Xenos - 06-03-2014 Et si vous avez une solution pour sélectionner toutes les cases côtières, quelque soit leur altitude (donc les cases ayant au moins une voisine maritime), plus rapide que celle ci-dessous qui dure des plombes (pour 500k cases dont les 2/3 sont de la mer), je suis preneur:
RE: Sélectionner les cases cotières d'une carte - niahoo - 06-03-2014 Pfff t'es vraiment obligé de mettre toutes ces quotes ? ça me fait bugger les yeux. Bref, donc déjà tu utilises les notations x/y et altitude, pourquoi ne pas plutôt mettre 'latitude', 'longitude', et 'z' ? :p Ensuite c'est pas logique que des cases aient une altitude négative par rapport à la mer et soient côtières. à moins que tu simules l'avancée des eaux. Dans tous les cas pourquoi ne pas simplement calculer tout ça à l'avance et le garder au chaud ? Oui je sais ça aide pas trop. RE: Sélectionner les cases cotières d'une carte - Ter Rowan - 06-03-2014 de la même manière que tu stockes mer, lorsque tu créés/modifies une case, ajouter l'attribut côte ? après je me pose la question si une case < 0 est à côté d'une case < 0 qui est elle même à côté d'une case mer, est ce qu'elle aussi ne devrait pas être inondée ? RE: Sélectionner les cases cotières d'une carte - Akhyra - 06-03-2014 Hello Est ce que ta carte est grande ? Est ce que l’inondation est réalisé par un cron/script ou en temps à l'affichage ? Si c'est réalisé par un cron, je serai passer par un traitement serveur (PHP), traitement plus long selon la grandeur de la carte mais qui te permet de mettre en place un algo d’inondation plus élaboré et modifiable par la suite. Je pense notamment à des cas ou tu ne voudrai pas inonder des cases adjacentes avec une certaine altitude, un certains type ou contenu. RE: Sélectionner les cases cotières d'une carte - niahoo - 06-03-2014 La carte fait 516k cases. RE: Sélectionner les cases cotières d'une carte - Xenos - 06-03-2014 @niahoo: Latitude/Longitude impliquent une carte sphérique, ce qui ne sera pas forcément le cas, d'où X/Y et altitude (et non Z car deux cases ne se superposent pas: l'altitude est une propriété de la case en XY plus qu'une coordonnée de la case). Le générateur de carte travaillant à partir d'une image PNG, le résultat n'est pas parfaitement exact, et des cases terrestres se retrouvent sous le niveau de la mer, en étant voisine de celle-ci :\ @Ter Rowan: Oui, dans le cas d'une case sous le niveau de la mer, voisine d'une case également sous le niveau de la mer, voisine elle-même d'une case maritime, les deux cases sous le niveau de la mer seront inondées. Cela se fera très bien par réccurence: noyer les cases cotières sous le niveau de la mer, ce qui crée de nouvelles cases maritimes, modifier la liste des cases cotières sachant lesquelles viennent d'être noyées, puis noyer les cases cotières sous le niveau de la mer voisine d'une case qui vient d'être noyée. Cette récurrence est en place, mais chaque "passage" (chaque tour de boucle) prend une dizaine de secondes, et comme le nombre de boucles peut monter à quelques centaines, cela fait vite très très long! Oui, j'ai tenté de stocker un autre attribut indiquant qu'une case est cotière, mais la requête pour générer cet attribut est interminable (cf 2nd post, requête sans le "case0.altitude <=0). @Akhyra: La carte contient environ 500k cases, dont 200k sont terrestres et 300k sont maritimes. Pour l'instant, l'inondation est réalisée uniquement au démarrage du jeu, pour l'initialiser. J'ai eu la même idée en me levant, passer par un PHP avec un tableau 2D de booléens "mer" pour créer un autre tableau de booléens 2D "estCotiere". Je viens de tester, et le résultat est assez satisfaisant. Je vais essayer de faire le même procédé en SQL. Pour information, en voici le code:
Temps (500k cases dont 24k cases côtières): 5secondes Mémoire (carte 1440*720 contenant 500k cases): 165Mo Merci du coup de main RE: Sélectionner les cases cotières d'une carte - niahoo - 06-03-2014 Genre un carré de 718 cases de côté (mais je suppose que c'est plutôt un rectangle dans le cas présent). RE: Sélectionner les cases cotières d'une carte - Akhyra - 06-03-2014 Retour rapide, pourquoi stocker seulement une valeur 1 ou 0 dans les coordonnées de la case ? J'ai pas fait de test, mais stocker la ligne SQL sous format array me parait pas délirant sur les ressources, ca te permettra si besoin par la suite d'avoir toutes les infos de la case pour modifier l'algo. RE: Sélectionner les cases cotières d'une carte - Xenos - 06-03-2014 Parce que pour la détection des côtes, je n'ai pas besoin de plus. Je suis déjà à 165Mo en mémoire (ah, la terrible optimisation de la mémoire en PHP :p), si je rajoute d'autres données, (en remplaçant la valeur entière par un tableau correspondant aux données de la ligne SQL) je dépasserai facilement le giga... Finalement, j'ai opté pour:
Le résultat est rapide (quelques secondes), sans exploser la taille en mémoire pour le PHP. J'aurai pu insérer les "IdVoisinN" dans une table séparée (type "IdCase1", "IdCase2", symbolisant deux cases voisines) mais étant donné que je n'ai que 4 voisins pour chaque case, une table supplémentaire aurait été plus lourd à gérer. En pratique, le goulot d'étranglement qui fait exploser la durée du traitement vient de l'indexation (x,y) (ou (y,x) dans mon cas): l'utilisation de deux arbres binaires (BTREE) comme le fait MySQL n'est absolument pas optimisé pour la recherche des voisins d'une case. Par curiosité, je vais tenter d'utiliser le format spatial de MySQL. Je vous rapporterai les résultats |