Utilisation de std::list [Résolu]

wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 29 oct. 2012 à 15:45 - Dernière réponse : cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention
- 13 déc. 2012 à 14:05
Salut tout le monde !

Je suis en train de coder un algo de A* pour résoudre le jeu du sokoban.
Je n'ai pas de problème particulier avec l'algo en lui même mais plutôt avec les variables que j'utilise.

Mon problème est simple, je crée des Node contenant un chemin possible (avec un poids, un cout, etc...) et je les push_back dans 2 std::list différentes. Lorsque je pousse le premier tout va bien, mais ensuite (et sans aucune volonté de ma part) les Node contenu dans ces listes deviennent du grand n'importe quoi...

Je pense que j'utilise mal les std::list mais je ne suis pas sûr. J'ai donc coder l'algo de nouveau (from scratch) mais je me retrouve encore avec le même problème...

Tout le code et les fichiers textes sont ici : http://quentin.rubis.free.fr/Sokoban_solver.rar
Le tout dans un projet code blocks. Le reste des fonctions marchent correctement et servent à lire les fichiers textes pour la map etc...

J'attend vos suggestions avec impatience :D

Petit aperçu du contenu des listes :
Afficher la suite 

Votre réponse

21 réponses

Meilleure réponse
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 30 oct. 2012 à 17:48
3
Merci
Je t'ai refait la classe Map, en un peu plus propre. Ne serait-ce que la fonction de load (10 fois moins grosse et qui fait la même chose).
Pour l'analyse du problème des autres classes, ça arrive.

main.cc
#include "Map.hh"
#include 

int main()
{
  const std::string filename =  "map.txt";
  Sokoban::Map map;
  if (!map.load(filename))
  {
    std::cerr << "Error while loading: " << filename << std::endl;
    return 1;
  }

  std::cout << "Rows: " << map.getNbRows() << std::endl
    << "Cols: " << map.getNbCols() << std::endl
    << "Gems: " << map.getNbGems() << std::endl
    << map << std::endl;

  std::cout << "Test (3, 2) is: " << map(3, 2) << std::endl
    << "     (6, 5) is: " << map(6, 5) << std::endl
    << "     (7, 4) is: " << map(7, 4) << std::endl;

  return 0;
}


Map.hh
#ifndef MAP_HH_
# define MAP_HH_

# include <string>
# include <vector>

namespace Sokoban
{
  class Map
  {
  public:
    Map();
    bool load(const std::string& filename);
    void display(std::ostream& out) const;

    unsigned int getNbRows() const;
    unsigned int getNbCols() const;
    unsigned int getNbGems() const;
    void clear();
    char operator()(unsigned int x, unsigned y) const;

  private:
    unsigned int _row;
    unsigned int _column;
    unsigned int _gemNumber;
    std::vector<char> _data;
  };

  std::ostream& operator<<(std::ostream& out, const Map& map);
} // Sokoban

#endif /* !MAP_HH_ */


Map.cc
#include "Map.hh"

#include <fstream>
#include <cassert>

namespace Sokoban
{
  Map::Map()
    : _row(0), _column(0), _gemNumber(0), _data()
  {
  }

  bool
  Map::load(const std::string& filename)
  {
    std::ifstream file(filename.c_str());
    if (!file)
      return false;

    file >> _column >> _row >> _gemNumber;
    file.ignore(1, '\n');
    if (_row < = 0 || _column <= 0)
      return false;

    _data.resize(_row * _column);
    std::string line;
    for (unsigned int x = 0; std::getline(file, line) && x < _row; ++x)
      for (unsigned int y = 0; y < _column; ++y)
_data[x * _column + y] = line[y];

    return true;
  }

  unsigned int
  Map::getNbRows() const
  {
    return _row;
  }

  unsigned int
  Map::getNbCols() const
  {
    return _column;
  }

  unsigned int
  Map::getNbGems() const
  {
    return _gemNumber;
  }

  void
  Map::clear()
  {
    _row = 0;
    _column = 0;
    _gemNumber = 0;
    _data.clear();
  }

  void
  Map::display(std::ostream& out) const
  {
    for (unsigned int x = 0; x < _row; ++x)
    {
      for (unsigned int y = 0; y < _column; ++y)
out << _data[x * _column + y];
      out << std::endl;
    }
  }

  char
  Map::operator()(unsigned int x, unsigned int y) const
  {
    assert(x < _row);
    assert(y < _column);
    return _data[x * _column + y];
  }

  std::ostream& operator<<(std::ostream& out, const Map& map)
  {
    map.display(out);
    return out;
  }
} // Sokoban


________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question

Merci cptpingu 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 69 internautes ce mois-ci

Commenter la réponse de cptpingu
Meilleure réponse
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 23 nov. 2012 à 16:15
3
Merci
Excuse moi du retard pour la validation de tes réponses, elles m'ont vraiment aidé!

Aucun souci, il n'y a pas de limite de temps :)

Pour ce qui est des droit sous linux j'ai laissé tomber

C'est dû à une installation un peu exotique. Tu as bien fait de te recentrer sur autre chose, inutile de perdre du temps sur cela. Je te conseille dans ce cas de juste copier le binaire généré sur ta partition Linux quand tu veux tester (pas très pratique, je te l'accorde).

J'ai fait des modifs un peu trop grosse sans faire assez de test... résultat ça plante partout (plutôt normal :P)

Petit conseil, maintenant évident pour toi: Toujours coder en incrémental ! C'est-à-dire réaliser des petites tâches et les tester et valider au fur et à mesure. Ne jamais faire passer un gros paté, c'est souvent l'échec ! (On est tous passé par là).

Je m'amuse donc avec le debuggeur mais là surprise, en debug tout va bien, en release ça plante au départ.

C'est tout à fait possible, et pour différente raisons qui peuvent-être:
- Tu as des valeurs assignés dans des "assert". Comme les assert disparaissent purement et simplement en release, ton code ne fonctionne correctement qu'en debug.
- Tu as une erreur de mémoire dans ton code, et le fait de passer ton code en release la met au grand jour (elle était toujours là, tapis dans l'ombre, mais tu ne la voyais pas :p).

Pour résoudre cela, plusieurs solutions:
* On compile avec DUMA en mode debug (c'est une biliothèque qui remplace automatiquement toutes tes allocations par des allocations spéciales qui détectent toutes erreurs mémoires).
* On compile sans DUMA mais en lançant un détecteur de problème mémoire sur ton binaire (via valgrind sous Linux). Ne nécessite pas de recompiler et fonctionne même en mode release.

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question

Merci cptpingu 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 69 internautes ce mois-ci

Commenter la réponse de cptpingu
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 29 oct. 2012 à 17:45
0
Merci
Bonjour.

Je veux bien t'aider, mais encore faut-il que tu présentes un code qui compile. C'est bourré d'erreurs de syntaxe !
Quelques exemples:
- aStar.cpp:280 => \\\\ Ce genre de caractère sert à échapper d'autre caractères. Si tu en as un nombre impair, tu échapes le saut de ligne ! (et comme tu en as 21 => warning: multi-line comment [-Wcomment])
- point.hpp:17 => bool operator==(Point::Point const& p1); devrait être bool operator==(Point const& p1); vu que tu es déja dans "Point". D'où le "error: ‘Point::Point’ is not a type".
- aStar.cpp:10 => "void aStar(const Map::Map *myMap, Node::Node *root, Point::Point destination)", Le Map::Map* devrait être un Map*, d'où le "error: ‘Map::Map’ names the constructor, not the type"

Il y a 173 lignes d'erreur, je ne vais donc pas toutes les faire !
J'ai essayé de compiler ton projet sous Linux, via:
g++ -W -Wall -pedantic aStar.cpp main.cpp map.cpp node.cpp point.cpp -o solver

Il y a beaucoup à dire sur le code (fonctionnellement, techniquement, au niveau du style, au niveau des conventions, etc...), sans même voir ce qu'il fait. Mais je préfère attendre que tu aies corrigé les erreurs avant d'aller plus loin.

Pour info, voici le log d'erreur suite à ma tentative de compilation:
aStar.cpp:280:1: warning: multi-line comment [-Wcomment]
In file included from map.hpp:4:0,
                 from aStar.cpp:4:
point.hpp:17:32: error: &#8216;Point::Point&#8217; is not a type
In file included from aStar.cpp:4:0:
map.hpp:16:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
map.hpp:17:32: error: &#8216;Point::Point&#8217; is not a type
map.hpp:24:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
In file included from aStar.cpp:5:0:
node.hpp:13:50: error: &#8216;Point::Point&#8217; is not a type
node.hpp:22:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
node.hpp:23:35: error: &#8216;Point::Point&#8217; is not a type
node.hpp:32:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
In file included from aStar.cpp:6:0:
aStar.hpp:5:18: error: &#8216;Map::Map&#8217; names the constructor, not the type
aStar.hpp:5:28: error: ISO C++ forbids declaration of &#8216;myMap&#8217; with no type [-fpermissive]
aStar.hpp:5:41: error: &#8216;Node::Node&#8217; is not a type
aStar.hpp:5:60: error: &#8216;Point::Point&#8217; is not a type
aStar.hpp:6:34: error: &#8216;lowerWeight&#8217; was not declared in this scope
aStar.hpp:6:47: error: expected primary-expression before &#8216;const&#8217;
aStar.hpp:6:70: error: expected primary-expression before &#8216;int&#8217;
aStar.hpp:6:83: error: expression list treated as compound expression in initializer [-fpermissive]
aStar.hpp:7:27: error: &#8216;lowerWeight&#8217; was not declared in this scope
aStar.hpp:7:40: error: expected primary-expression before &#8216;const&#8217;
aStar.hpp:7:63: error: expected primary-expression before &#8216;int&#8217;
aStar.hpp:7:76: error: expression list treated as compound expression in initializer [-fpermissive]
aStar.hpp:8:35: error: &#8216;Node::Node&#8217; cannot appear in a constant-expression
aStar.hpp:8:40: error: template argument 1 is invalid
aStar.hpp:8:40: error: template argument 2 is invalid
aStar.hpp:8:69: error: &#8216;Node::Node&#8217; cannot appear in a constant-expression
aStar.hpp:8:74: error: template argument 1 is invalid
aStar.hpp:8:74: error: template argument 2 is invalid
aStar.cpp:10:18: error: &#8216;Map::Map&#8217; names the constructor, not the type
aStar.cpp:10:28: error: ISO C++ forbids declaration of &#8216;myMap&#8217; with no type [-fpermissive]
aStar.cpp:10:41: error: &#8216;Node::Node&#8217; is not a type
aStar.cpp:10:60: error: &#8216;Point::Point&#8217; is not a type
aStar.cpp: In function &#8216;void aStar(const int*, int*, int)&#8217;:
aStar.cpp:15:21: error: &#8216;Node::Node&#8217; cannot appear in a constant-expression
aStar.cpp:15:26: error: template argument 1 is invalid
aStar.cpp:15:26: error: template argument 2 is invalid
aStar.cpp:15:36: error: invalid type in declaration before &#8216;;&#8217; token
aStar.cpp:16:21: error: &#8216;Node::Node&#8217; cannot appear in a constant-expression
aStar.cpp:16:26: error: template argument 1 is invalid
aStar.cpp:16:26: error: template argument 2 is invalid
aStar.cpp:16:37: error: invalid type in declaration before &#8216;;&#8217; token
aStar.cpp:18:17: error: &#8216;lowerWeightNode&#8217; was not declared in this scope
aStar.cpp:19:17: error: &#8216;lastNode&#8217; was not declared in this scope
aStar.cpp:21:14: error: request for member &#8216;push_back&#8217; in &#8216;openList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:33:22: error: request for member &#8216;size&#8217; in &#8216;openList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:37:27: error: request for member &#8216;size&#8217; in &#8216;openList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:39:33: error: request for member &#8216;begin&#8217; in &#8216;openList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:40:40: error: request for member &#8216;front&#8217; in &#8216;openList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:44:40: error: request for member &#8216;front&#8217; in &#8216;openList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:45:56: error: request for member &#8216;begin&#8217; in &#8216;openList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:48:37: error: request for member &#8216;end&#8217; in &#8216;openList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:72:23: error: request for member &#8216;splice&#8217; in &#8216;closeList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:72:41: error: request for member &#8216;begin&#8217; in &#8216;closeList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:82:62: error: &#8216;isValidMovement&#8217; cannot be used as a function
aStar.cpp:85:21: error: &#8216;Point::Point&#8217; names the constructor, not the type
aStar.cpp:85:34: error: expected &#8216;;&#8217; before &#8216;myCoordinate&#8217;
aStar.cpp:85:80: error: statement cannot resolve address of overloaded function
aStar.cpp:90:29: error: &#8216;myCoordinate&#8217; was not declared in this scope
aStar.cpp:109:42: error: &#8216;Node::Node&#8217; cannot appear in a constant-expression
aStar.cpp:109:47: error: template argument 1 is invalid
aStar.cpp:109:47: error: template argument 2 is invalid
aStar.cpp:109:59: error: invalid type in declaration before &#8216;it&#8217;
aStar.cpp:109:59: error: invalid use of qualified-name &#8216;::iterator&#8217;
aStar.cpp:109:59: error: expected &#8216;;&#8217; before &#8216;it&#8217;
aStar.cpp:109:59: error: &#8216;it&#8217; was not declared in this scope
aStar.cpp:109:72: error: request for member &#8216;begin&#8217; in &#8216;closeList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:109:95: error: request for member &#8216;end&#8217; in &#8216;closeList&#8217;, which is of non-class type &#8216;int&#8217;
aStar.cpp:109:100: error: expected &#8216;)&#8217; before &#8216;;&#8217; token
aStar.cpp:109:104: error: &#8216;it&#8217; was not declared in this scope
aStar.cpp:109:106: error: expected &#8216;;&#8217; before &#8216;)&#8217; token
aStar.cpp:107:26: warning: unused variable &#8216;isContainedInCloseList&#8217; [-Wunused-variable]
aStar.cpp:273:1: error: expected &#8216;}&#8217; at end of input
aStar.cpp:273:1: error: expected &#8216;}&#8217; at end of input
aStar.cpp:273:1: error: expected &#8216;}&#8217; at end of input
aStar.cpp:273:1: error: expected &#8216;}&#8217; at end of input
aStar.cpp:273:1: error: expected &#8216;while&#8217; at end of input
aStar.cpp:273:1: error: expected &#8216;(&#8217; at end of input
aStar.cpp:273:1: error: expected primary-expression at end of input
aStar.cpp:273:1: error: expected &#8216;)&#8217; at end of input
aStar.cpp:273:1: error: expected &#8216;;&#8217; at end of input
aStar.cpp:273:1: error: expected &#8216;}&#8217; at end of input
In file included from map.hpp:4:0,
                 from main.cpp:3:
point.hpp:17:32: error: &#8216;Point::Point&#8217; is not a type
In file included from main.cpp:3:0:
map.hpp:16:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
map.hpp:17:32: error: &#8216;Point::Point&#8217; is not a type
map.hpp:24:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
In file included from main.cpp:4:0:
node.hpp:13:50: error: &#8216;Point::Point&#8217; is not a type
node.hpp:22:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
node.hpp:23:35: error: &#8216;Point::Point&#8217; is not a type
node.hpp:32:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
In file included from main.cpp:5:0:
aStar.hpp:5:18: error: &#8216;Map::Map&#8217; names the constructor, not the type
aStar.hpp:5:28: error: ISO C++ forbids declaration of &#8216;myMap&#8217; with no type [-fpermissive]
aStar.hpp:5:41: error: &#8216;Node::Node&#8217; is not a type
aStar.hpp:5:60: error: &#8216;Point::Point&#8217; is not a type
aStar.hpp:6:34: error: &#8216;lowerWeight&#8217; was not declared in this scope
aStar.hpp:6:47: error: expected primary-expression before &#8216;const&#8217;
aStar.hpp:6:70: error: expected primary-expression before &#8216;int&#8217;
aStar.hpp:6:83: error: expression list treated as compound expression in initializer [-fpermissive]
aStar.hpp:7:27: error: &#8216;lowerWeight&#8217; was not declared in this scope
aStar.hpp:7:40: error: expected primary-expression before &#8216;const&#8217;
aStar.hpp:7:63: error: expected primary-expression before &#8216;int&#8217;
aStar.hpp:7:76: error: expression list treated as compound expression in initializer [-fpermissive]
aStar.hpp:8:35: error: &#8216;Node::Node&#8217; cannot appear in a constant-expression
aStar.hpp:8:40: error: template argument 1 is invalid
aStar.hpp:8:40: error: template argument 2 is invalid
aStar.hpp:8:69: error: &#8216;Node::Node&#8217; cannot appear in a constant-expression
aStar.hpp:8:74: error: template argument 1 is invalid
aStar.hpp:8:74: error: template argument 2 is invalid
main.cpp: In function &#8216;int main()&#8217;:
main.cpp:14:17: error: &#8216;root&#8217; was not declared in this scope
main.cpp:14:28: error: expected type-specifier
main.cpp:14:28: error: expected &#8216;;&#8217;
main.cpp:15:31: error: &#8216;class Map&#8217; has no member named &#8216;getPlayerPosition&#8217;
main.cpp:17:41: error: cannot call constructor &#8216;Point::Point&#8217; directly [-fpermissive]
main.cpp:17:41: error:   for a function-style cast, remove the redundant &#8216;::Point&#8217; [-fpermissive]
main.cpp:19:12: error: type &#8216;<type error>&#8217; argument given to &#8216;delete&#8217;, expected pointer
In file included from map.hpp:4:0,
                 from map.cpp:1:
point.hpp:17:32: error: &#8216;Point::Point&#8217; is not a type
In file included from map.cpp:1:0:
map.hpp:16:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
map.hpp:17:32: error: &#8216;Point::Point&#8217; is not a type
map.hpp:24:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
map.cpp: In constructor &#8216;Map::Map(char*)&#8217;:
map.cpp:80:25: error: &#8216;playerPosition&#8217; was not declared in this scope
map.cpp:80:58: error: cannot call constructor &#8216;Point::Point&#8217; directly [-fpermissive]
map.cpp:80:58: error:   for a function-style cast, remove the redundant &#8216;::Point&#8217; [-fpermissive]
map.cpp: At global scope:
map.cpp:104:29: error: &#8216;char Map::getContent&#8217; is not a static member of &#8216;class Map&#8217;
map.cpp:104:35: error: expected &#8216;)&#8217; before &#8216;_point&#8217;
map.cpp:104:41: error: cannot resolve overloaded function &#8216;Point&#8217; based on conversion to type &#8216;char&#8217;
map.cpp:104:43: error: expected &#8216;,&#8217; or &#8216;;&#8217; before &#8216;const&#8217;
map.cpp:116:1: error: &#8216;Point::Point&#8217; names the constructor, not the type
In file included from node.hpp:6:0,
                 from node.cpp:1:
point.hpp:17:32: error: &#8216;Point::Point&#8217; is not a type
In file included from node.cpp:1:0:
node.hpp:13:50: error: &#8216;Point::Point&#8217; is not a type
node.hpp:22:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
node.hpp:23:35: error: &#8216;Point::Point&#8217; is not a type
node.hpp:32:9: error: &#8216;Point::Point&#8217; names the constructor, not the type
node.cpp: In constructor &#8216;Node::Node()&#8217;:
node.cpp:8:5: error: &#8216;coordinate&#8217; was not declared in this scope
node.cpp:8:34: error: cannot call constructor &#8216;Point::Point&#8217; directly [-fpermissive]
node.cpp:8:34: error:   for a function-style cast, remove the redundant &#8216;::Point&#8217; [-fpermissive]
node.cpp: At global scope:
node.cpp:14:48: error: &#8216;Point::Point&#8217; is not a type
node.cpp: In constructor &#8216;Node::Node(int, int, int, int, Node*)&#8217;:
node.cpp:18:5: error: &#8216;coordinate&#8217; was not declared in this scope
node.cpp: At global scope:
node.cpp:54:1: error: &#8216;Point::Point&#8217; names the constructor, not the type
node.cpp:60:33: error: variable or field &#8216;setCoordinate&#8217; declared void
node.cpp:60:39: error: expected &#8216;)&#8217; before &#8216;_coordinate&#8217;
node.cpp: In member function &#8216;void Node::display()&#8217;:
node.cpp:78:39: error: &#8216;coordinate&#8217; was not declared in this scope
In file included from point.cpp:1:0:
point.hpp:17:32: error: &#8216;Point::Point&#8217; is not a type
point.cpp:26:20: error: &#8216;Point::Point&#8217; names the constructor, not the type
point.cpp:26:34: error: ISO C++ forbids declaration of &#8216;myPoint&#8217; with no type [-fpermissive]
point.cpp:26:1: error: prototype for &#8216;Point::Point(const int&)&#8217; does not match any in class &#8216;Point&#8217;
point.hpp:15:9: error: candidates are: Point::Point(const Point&)
point.cpp:11:1: error:                 Point::Point(int, int)
point.cpp:4:1: error:                 Point::Point()
point.cpp:42:37: error: declaration of &#8216;operator==&#8217; as non-function
point.cpp:42:37: error: expected &#8216;)&#8217; before &#8216;const&#8217;


________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 30 oct. 2012 à 11:34
0
Merci
Merci de ton post, je vais avoir besoin de temps...
Je travaille sous windows et j'ai les mêmes flags de compil que toi, pourtant je n'ai pas tout ces messages d'erreurs (qui sont pourtant justifiés).
Je passe sous linux je répare tout et si le problème persiste je reviens vers toi.

+
Commenter la réponse de wilvart
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 30 oct. 2012 à 11:50
0
Merci
Je travaille sous windows et j'ai les mêmes flags de compil que toi

Le problème sous Windows, c'est que c'est souvent une vieille version de gcc qui est installée (via mingw ou cygwin). Les vieilles versions sont moins performantes sur la détection d'erreurs, et beaucoup plus permissives. J'ai un gcc récent (4.6.3), de là doit venir la différence.

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 30 oct. 2012 à 12:08
0
Merci
Bon tout et réparé, le code uploadé.
J'ai par contre un problème pour exécuter 'solver' (en utilisant la même commande de compil que toi). J'ai un 'permission denied'.

En créant l'exe sous windows, mon premier problème persiste...


Au passage, j'ai regardé pas mal de tuto sur les #include. Ce qu'il en sort est qu'il ne faut pas trop en mettre dans les .hpp, il y aurait-il une autre façon de faire? (je prend pour exemple node.hpp dans lequel je dois include point.hpp
Commenter la réponse de wilvart
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 30 oct. 2012 à 13:35
0
Merci
J'ai par contre un problème pour exécuter 'solver' (en utilisant la même commande de compil que toi). J'ai un 'permission denied'.

Vérifie les droits sur ton binaire. Tape un "chmod 755 solver" avant de faire un "./solver".

En créant l'exe sous windows, mon premier problème persiste...

C'est normal, tu as corrigé les erreurs de syntaxe (pour que je puisse y jeter un coup d'oeil) mais tu n'as pas corrigé le problème. Je t'analyse ça et je reviens vers toi.

Au passage, j'ai regardé pas mal de tuto sur les #include. Ce qu'il en sort est qu'il ne faut pas trop en mettre dans les .hpp, il y aurait-il une autre façon de faire? (je prend pour exemple node.hpp dans lequel je dois include point.hpp

Tu fais ce que tu veux avec les includes. Le compilateur est intelligent et fera en sorte que ça fonctionne. En revanche, il est vrai que faire des includes propres, c'est-à-dire inclure *uniquement* ce qui est strictement nécessaire accèlère le temps de compilation (vu que le compilo a des graphes moins violents à tracer pour gérer les includes). Mais à moins d'avoir un gros gros projet, tu ne le sentiras pas.
Je t'invite néanmoins à n'inclure que le stricte minimum à chaque fois (c'est-à-dire dans le .cpp plutôt que dans le .hpp) dès que tu le peux. C'est une très bonne pratique qui aide à la lisibilité et à la vitesse compilation sur de gros projets.

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 30 oct. 2012 à 13:47
0
Merci
Plusieurs soucis.

I. Méthodologie:

C'est une erreur que tu aurais pu trouver toi même via un débuggeur. Je vais te donner ma démarche pour te montrer comment j'ai trouvé ton erreur en 1 min.
1) Compilation en debug: g++ -W -Wall -pedantic aStar.cpp main.cpp map.cpp node.cpp point.cpp -g -o solver
2) Lancement du programme dans un débuggeur: gdb ./solver
3) Lancement du programme: r (puis entrée dans gdb)
4) Analyse de la batcktrace via la commande "bt", ce qui donne:


gdb$ bt
#0 0x00007ffff753b425 in __GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00007ffff753eb8b in __GI_abort () at abort.c:91
#2 0x00007ffff757939e in __libc_message (do_abort=2, fmt=0x7ffff7683008 "*** glibc detected *** %s: %s: 0x%s ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:201
#3 0x00007ffff7583b96 in malloc_printerr (action=3, str=0x7ffff76831f8 "double free or corruption (fasttop)", ptr=<optimized out>) at malloc.c:5007
#4 0x0000000000403b96 in Node::~Node (this=0x7fffffffdc70, __in_chrg=<optimized out>) at node.cpp:29
#5 0x0000000000401af6 in aStar (myMap=0x7fffffffdde0, root=0x609260, destination=...) at aStar.cpp:152
#6 0x00000000004031c0 in main () at main.cpp:17


Ici, on voit bien que la ligne 152 de aStar.cpp pose problème.

5) Analyse du code
                    // If the node is not in the openList, add it to. Else, replace it if better
                    if (!isContainedInOpenList)
                    {
                        Node myNode(heuristicValue, i, myCoordinate, lowerWeightNode->getMovementCost() +1, lowerWeightNode);
                        openList.push_back(&myNode);

                        /////////////////////////
                        // Display the added node
                        std::cout << "Added node because not contained in openList :" << std::endl;
                        myNode.display();
                        std::cout << std::endl << std::endl;
                    }


Et là, on voit que tu fais rentrer myNode dans ton openList, alors que myNode sera détruit automatiquement ligne 153 (vu que c'est une variable locale).
Pour corriger cela, il te faut remplacer:
Node myNode(heuristicValue, i, myCoordinate, lowerWeightNode->getMovementCost() +1, lowerWeightNode);
openList.push_back(&myNode);

par:
Node* myNode = new Node(heuristicValue, i, myCoordinate, lowerWeightNode->getMovementCost() +1, lowerWeightNode);
openList.push_back(myNode);



Il y a des soucis techniques (II.), de style (III.), d'architecture (IV.), et j'en passe. Je te les liste et je te posterais ça dès que j'aurais fini.

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 30 oct. 2012 à 13:56
0
Merci
Je vais découper mes explications en plusieurs postes, parce qu'il y a beaucoup à dire.

Commençons par les includes. Il te faut mettre un include uniquement si utilises un élément qui est dans cet include.
Par exemple, dans aStar.cpp, il manque des includes.
Ne serait-ce que pour: "void displayLists(std::list<Node*> &openList, std::list<Node*> &closeList, std::string id);" il te faut inclure: Node, list et string. Ici ça fonctionne car dans le .cpp tu les a inclus, et par accident, le .hpp étant inclus en dessous, tu en profites et ça compile.

Dans la théorie, je te conseille de faire les choses suivantes:
- Dans le .hpp, tu inclus tout ce dont tu as besoin dans le header. Si tu utilise un std::list dans une de tes signatures de fonctions, alors <list> doit être dans le .hpp !
- A contrario, si tu utilises un std::cout dans le .cpp, mais pas dans le .hpp alors l'include ira dans le .cpp mais pas dans le .hpp
- Enfin, quand tu fais des includes, inclus toujours d'abord tes headers avant les headers standards. Ça t'évitera d'oublier des includes par incidence. Ex:
#include 
#include 
#include <list>
#include "map.hpp"
#include "node.hpp"
#include "aStar.hpp"


devrait être:
// En premier le .hpp qui va avec ton .cpp
#include "aStar.hpp"

// Vient ensuite tes propres headers
#include "map.hpp"
#include "node.hpp"

// Et enfin les headers systèmes.
#include 
#include 
#include <list>


C'est à mons sens la manière la plus propre d'inclure quelque chose en C/C++.

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 30 oct. 2012 à 16:24
0
Merci
II. Problème techniques

Je vais reprendre toutes tes classes une par une.

[b]main.cpp
/b
Si tu crées un objet pour le détruire de suite, inutile de l'allouer manuellement.
Ex:
 Node* root =  new Node();
 root->setCoordinate(myMap.getPlayerPosition());
 aStar(&myMap, root, Point(1,1));
 delete root;


devrait être:
 Node root;
 root.setCoordinate(myMap.getPlayerPosition());
 aStar(&myMap, &root, Point(1,1));


Classe Map.

- Le constructeur devrait prendre un const std::string& plutôt qu'un char* (ou au moins un const char* !).
- Une fonction ne devrait pas dépasser un cinquantaine de ligne. Il y a sinon une forte chance qu'il y ait une erreur de conception ou un mauvais découpage de fonction.
- Utilise 0 plutôt que NULL (ou alors nullptr si tu es en C++0x).
- A la place d'un char** content, j'aurais plutôt fait un std::vector<Cell> en utilisant la technique index = (x * index + y) pour aplanir un tableau à deux dimensions dans un seul (vu que tu ne gères que tableau dont tout les lignes ont le mêmes nombres de colonnes).
Tu peux réutiliser ou t'inspirer de: https://github.com/cptpingu/game/blob/master/src/Core/Array2D.hh
- Je mettrais le load de la map dans une méthode load plutôt que dans le constructeur (quitte à appeler load() dans le constructeur).
- myFile.close() ne sert à rien. Un std::fstream se ferme tout seul.
- Une fonction n'écrit jamais sur std::cout, elle devrait retourner un code d'erreur, pour l'utilisateur de ta classe. Ce n'est pas à la classe d'écrire.
- void Map::display() => devrait être void Map::display(std::ostream& out) const. Au lieu d'écrire dans std::cout, tu écrirais alors dans out. Encore une fois, les fonctions internes ne doivent pas écrire dans std::cout, c'est l'utilisateur de la classe qui doit avoir ce controle et tu ne fais que lui remonter.
- J'ajouterais une surcharge sur operator() pour faciliter l'accès.

Je te joins une proposition de réecriture propre au post suivant, avant de m'attaquer aux autres classes.

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 31 oct. 2012 à 13:47
0
Merci
Merci beaucoup de ton aide, mais je vais refaire les classes moi même, au moins j'apprendrais plus facilement.

Le fait de créer des pointeurs de Node à bien sur tout changé :D Je recommence de ce point là pour essayer de trouver mon problème.

Je veux bien un dernier conseil par contre. Même arès le chmod 755 ou le chmod +x, mon 'exe' reste en permission denied. J'ai vu un article sur stackoverflow qui situait le problème sur le fait que mon 'exe' est sur une partition séparée est que les droits que j'ai après le mount ne sont pas suffisant pour executer un programme... Je suis un peu perdu à partir de là..

Encore merci pour ton aide !
Commenter la réponse de wilvart
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 31 oct. 2012 à 14:01
0
Merci
Merci beaucoup de ton aide, mais je vais refaire les classes moi même, au moins j'apprendrais plus facilement.

Je t'invite à bien regarder le code de Map, qui contient des bonnes pratiques (découpage de modules en les nommant via un namespace, utilisation propre de std::ifstream, convention de nommage et alignement, sécurité via "assert", redéfinition propre d'opérateurs, et quelques astuces bien pratique comme le file.ignore ou le _data.resize).
Je te conseillerais tout de même d'utiliser cette classe, vu que ça ne représente qu'une toute petite partie de ton projet.


Je veux bien un dernier conseil par contre. Même arès le chmod 755 ou le chmod +x, mon 'exe' reste en permission denied. J'ai vu un article sur stackoverflow qui situait le problème sur le fait que mon 'exe' est sur une partition séparée est que les droits que j'ai après le mount ne sont pas suffisant pour executer un programme...

N'ayant pas ta table des partitions sous les yeux, il m'est difficile de répondre. Mais la chose suivante est possible:

1)
- Tu as un double boot Win/Linux. Tu as une partition pour Windows, une pour Linux, et une commune pour les deux.
- Cette partition commune est en FAT32 ou NTFS. Or je me souvients avoir eu des problèmes de droits sur ce genre de format (à l'époque, on pouvait lire sur du NTFS, mais pas écrire dessus ! C'est aujourd'hui possible et quasiment supporté par toutes les distributions de base).
- Essaie de copier ton binaire sur une partition ext3 ou ext4.

2)
- Tu as installé Ubuntu via Wubi.
- Fais une installation propre, Wubi c'est pratique, mais c'est horriblement moche !
- Tu peux aussi utiliser une VM (VirtualBox par exemple).

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 31 oct. 2012 à 14:20
0
Merci
Deuxième option, j'ai créé 3 partitions, une pour Win7, une Data et une pour Ubuntu. J'ai utilisé wubi pour installer Ubuntu.

En allant dans les propriétés de ma partition, je peux voir les droits. Je suis autorisé à tout faire... ou pas.

Je peux te donner plus d'info?
Commenter la réponse de wilvart
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 31 oct. 2012 à 14:59
0
Merci
Je sais que Wubi pose pas mal de problème. Il aurait été mieux de graver un iso d'Ubuntu et d'installer un double boot via le CD plutôt que d'utiliser Wubi :(.
Impossible de t'aider dans ces conditions particulières.

Si ceci ne fonctionne pas, je ne pourrais rien faire pour toi:
- Copie le binaire sur ta partition Ubuntu et pas Data.
- chmod 755 solver
- chgroup <ton_login> solver
- sudo chown <ton_login> solver
- ./solver (et pas "solver").

Si ça ne fonctionne toujours pas, je ne vois pas :(.

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 23 nov. 2012 à 16:00
0
Merci
Salut,

Excuse moi du retard pour la validation de tes réponses, elles m'ont vraiment aidé!
Mon code est beaucoup plus propre et facil à gérer.

Pour ce qui est des droit sous linux j'ai laissé tomber... Je sais que le problème vient du fait que je suis sur une partition mais tout ce que j'ai pu essayer n'a rien donné (mis à part copier le projet sur la partition linux, ce qui ne m'arrange pas).

Si tu me le permet j'aimerais avoir une info sur un problème.
J'ai fait des modifs un peu trop grosse sans faire assez de test... résultat ça plante partout (plutôt normal :P)
Je m'amuse donc avec le debuggeur mais là surprise, en debug tout va bien, en release ça plante au départ.
Les infos que j'ai trouvé sur google ne m'ont aidé en rien. Ton expérience me serait donc utile.

++
Commenter la réponse de wilvart
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 26 nov. 2012 à 16:23
0
Merci
J'adoooooooore valgrind ! et j'ai besoin de relire mon cours sur les pointeurs/allocations mémoires....

Plus de crash incompréhensibles, juste des erreurs communes ouf !

Merci !
Commenter la réponse de wilvart
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 28 nov. 2012 à 22:14
0
Merci
Re-re-re-re-salut,

Je suis sur une bonne passe, même si mon algo a encore quelques défauts.

J'aimerais te demander ton avis sur l'utilisation des pointeurs, en particulier la suppression. (Tu trouvera le nouveau code ici : http://quentin.rubis.free.fr/Sokoban_solver.rar)

Le rapport de valgrind me dis ceci :

= =2716== HEAP SUMMARY:
2716== in use at exit: 49,404 bytes in 1,525 blocks
2716== total heap usage: 8,717 allocs, 7,192 frees, 238,460 bytes allocated
2716==
2716== 2,028 (144 direct, 1,884 indirect) bytes in 1 blocks are definitely lost in loss record 10 of 18
2716== at 0x4C2AF8E: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
2716== by 0x40A1E7: Sokoban::aStarDiamond(Sokoban::Node&, Sokoban::Point) ( aStarDiamond.cpp:163 )
== 2716== by 0x407392: Sokoban::solve(Sokoban::Map&) (solver.cpp:19)
2716== by 0x40199F: main (main.cpp:28)
2716==
2716== 3,144 (288 direct, 2,856 indirect) bytes in 2 blocks are definitely lost in loss record 13 of 18
2716== at 0x4C2AF8E: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
2716== by 0x40A05A: Sokoban::aStarDiamond(Sokoban::Node&, Sokoban::Point) ( aStarDiamond.cpp:148 )
== 2716== by 0x407392: Sokoban::solve(Sokoban::Map&) (solver.cpp:19)
2716== by 0x40199F: main (main.cpp:28)
2716==
2716== 44,232 (7,344 direct, 36,888 indirect) bytes in 51 blocks are definitely lost in loss record 18 of 18
2716== at 0x4C2AF8E: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
2716== by 0x40815E: Sokoban::aStarPlayer(Sokoban::Node&, Sokoban::Point) ( aStarPlayer.cpp:145 )
==2716== by 0x40B563: Sokoban::canPlayerMoveBehind(Sokoban::Node*, int) (aStarDiamond.cpp:324)
2716== by 0x409C91: Sokoban::aStarDiamond(Sokoban::Node&, Sokoban::Point) (aStarDiamond.cpp:82)
2716== by 0x407392: Sokoban::solve(Sokoban::Map&) (solver.cpp:19)
2716== by 0x40199F: main (main.cpp:28)
2716==
2716== LEAK SUMMARY:
2716== definitely lost: 7,776 bytes in 54 blocks
2716== indirectly lost: 41,628 bytes in 1,471 blocks
2716== possibly lost: 0 bytes in 0 blocks
2716== still reachable: 0 bytes in 0 blocks
2716== suppressed: 0 bytes in 0 blocks
2716==
2716== For counts of detected and suppressed errors, rerun with: -v
2716== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 2 from 2)


Soit que je ne détruit pas les pointeurs de Node aux lignes indiquées. (plus une ligne dans aStarplayer mais elle est identique aux autres, simplement pas utilisée pour cette map).

J'ai bien essayé de delete chaque éléments de openList et closeList mais le résultat est un gros plantage pas très propre... Qu'est ce que je peux faire pour ça?

plouch !
Commenter la réponse de wilvart
cptpingu 3797 Messages postés dimanche 12 décembre 2004Date d'inscription 13 août 2018 Dernière intervention - 29 nov. 2012 à 15:35
0
Merci
Re-re-re-bonjour.

Il y a pas mal de soucis dans ton code, je ne vais pas tous les détailler mais en donner les grandes lignes:
- Une fonction bien conçue n'excède pas une cinquantaine de ligne. Ta fonction de aStar dépasse les 180 lignes... Il faut absolument que tu découpes ton code en petite fonction.
- Le choix du passages des données est très hasardeux. Tu passes en copie du constructeur de ton Node une liste construite vide ?! De même, "getPath()" retourne la liste par copie, ce qui n'est vraiment pas terrible.
- Utilise des listes d'initialisation, plutôt que d'affecter des valeurs dans le coprs du constructeur.
- Attention aux copies (très) couteuses ! Si tu oublies de passer un objet par référence, ça peut faire mal. Je pense notemment à la méthode: void Node::setMap(Map map) qui fait une copie de la map (et comme la map a plusieurs listes, niveau perfs...). Si dans node, ton seul but est d'avoir un accès à la map, alors la variable _map devrait juste être un pointeur. Actuellement, la méthode setMap réalise une double copie (une fois lors du passage en argument, et une fois lors du "=").
Je verrais plus un void Node::setMap(const Map* map) avec _map qui serait un pointeur. Tu as ce genre de soucis un peu partout.
- Évite les concaténations de std::string via "+". Préfère utiliser un std::ostringstream, bien plus adapté à des concaténations de string rapides (le "+" est assez catastrophique en terme de vitesse et d'utilisation mémoire => beaucoup de copies cachées). Le "+" n'est à utiliser que pour des tout petit string, ou une seule concaténation (et encore, ça reste limite).

Pour ton problème de mémoire:
Tu alloues des "Node", que tu mets dans une liste. Plus loin dans ton code, tu retires des nodes de ta liste. Mais tu ne désalloues jamais ces Nodes. Retirer un "Node*" d'une liste ne va pas le delete automatiquement. Il faut bien différencier, "je suis dans la liste" et "j'existe".

Ps: Un petit Makefile, ça serait tout de même bien agréable quand tu partages un code :)

________________________________________________________________________
Historique de mes créations, et quelques articles:
[ http://0217021.free.fr/portfolio http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
Commenter la réponse de cptpingu
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 13 déc. 2012 à 12:42
0
Merci
Salut !

Je viens de faire quelques modifs (les strings, le Makefile, la mémoire ...) mais il me reste encore petits problèmes.

- Diviser mes fonctions aStar est pour le moment 'optionnel', le code fonctionne et c'est un gros changement que je préfère éviter la tout de suite :) Mais ça viendra pour sur !

- Pour le choix du passage des données je suis un peu dans le brouillard. Et ce n'est pas à toi de savoir tout de mon code, donc je vais te donner des pistes et tu pourras me dire si elles sont bonnes à suivre.
Par exemple getPath(), j'ai essayer de lui faire retourner une référence de list au lieu d'une copie. J'ai un jolie segFault. Je pense que ça vient de l'utilisation de la list plus loin dans le code. Dans le sens où j'ai surement besoin de modifier cette liste (pour une quelconque raison). Enfin bon toujours est-il que je dois avoir ce genre de problème absolument partout.
Pour setMap() le problème est réglé, ce setteur était inutile.
Si tu as des conseils pour ce sujet je prend ! :P

- Les listes d'initialisation c'est fait !

- Les concaténations de strings sont réglées aussi

- Le dernier problème, la mémoire. J'ai bien delete les nodes avant de supprimer leurs pointeurs de mes listes, et la différence est là, mais j'ai encore des fuites que je ne sais pas boucher. D'après valgrind elles seraient au même endroit.

- J'ai fais un Makefile qui ne recompile que ce qui a été modifié, je pense que c'est pas extrêmement utile pour un petit projet comme le mien mais ça fait propre ! Il y a aussi un "make valgrind" pour aller plus vite

++
Commenter la réponse de wilvart
wilvart 47 Messages postés samedi 7 janvier 2006Date d'inscription 13 décembre 2012 Dernière intervention - 13 déc. 2012 à 12:46
Commenter la réponse de wilvart

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.