0

所以我试图从一个简单的迷宫游戏的文本文件中读取以下格式的数据:

A * B * *
B * C * A
CGD * B
D * * * C
EIF * *
FJG * E
G * HCF
H * * * G
IE *
J * KF *
K * L * J
L * * * K

第一列是当前节点。第二列,其正北的节点。第三,紧邻东部,第四,紧邻南部,第五,紧邻西部。任何 * 表示没有节点,指针应设置为 null。

请记住,我是 OOP 的新手,我很好奇如何将这些信息“保存”到一个名为 Node.js 的类中。

我有以下类定义:

public:
    int BuildGraph();
    char name;
    char north;
    char east;
    char south;
    char west;
};  
    std::vector<Node> nodes;

使用代码build >> node.name >> node.north >> node.east >> node.south >> node.west;读入正确的字符。

这正确地得到了我想要的字符。但是,一旦我到达该行的末尾,我如何存储这个节点然后移动到下一行并存储那个节点?现在,我有一个 do/while 循环,它循环直到它到达文件的末尾,但当然它每次都会覆盖所有内容,所以它有效读取的唯一代码是 L * 的最后一行* * K. 如何让第一行保存为节点 A,第二行保存为节点 B,等等?我如何在程序的其他地方引用它?现在,我只是在创建一个 Node 类型的对象节点。当我到达行尾时,我需要将节点中的所有内容复制到一个名为 A 的新节点。

编辑:对不起格式;Stack Overflow 没有将我的 4 个空格识别为代码缩进。

4

5 回答 5

1

I'm not sure if I'm getting what is what you want to get, but if you want to save each element of type Node with a different identifier you may try the next:

pair<char, Node> node_with_name;

And then you can assign the name to the first element doing build >> node_with_name.first; , then put the rest of the elements in the node and assign it in the same way to the second position of the pair.

And the vector should also be changed in order to use this solution:

std::vector<pair<char, Node> > nodes;

And finally you would do:

nodes.push_back(node_with_name);

in every iteration of the loop.


Edit: I think that a map would possibly fit better to your needs. I will show you an example:

std::map<char,Node> mymap;

do {
  char name;                          // to store temporarily each node's name
  build >> name;            
  build >> mymap[name].north;      // we start getting the data for the node with this name
  build >> mymap[name].east;
  build >> mymap[name].south;
  build >> mymap[name].west;
}while(! build.eof());

And then you can output each node's data with:

std::cout << "mymap['A'].north is " << mymap['A'].north << '\n';

Map reference: http://www.cplusplus.com/reference/map/map/operator%5B%5D/

Pair Reference: http://www.cplusplus.com/reference/utility/pair/

于 2013-07-25T01:07:42.110 回答
0

在文件上使用 getline() 函数,逐行读取文件并将节点信息解析到节点结构中。

于 2013-07-25T00:38:19.240 回答
0

据我了解,您希望能够从文件中读取节点的描述并将它们存储在内存中的数据结构中。看起来像一个文字冒险地图。

我已将您的迷宫游戏地图复制到名为“maze.dat”的文本文件中

这是一个简单的程序,它逐行解析 maze.dat 文件,将每一行存储到一个名为 Node 的用户定义数据结构中。然后将每个节点放置在另一个称为向量的数据结构中。

在程序结束时,我打印出向量中的每个节点,以便您可以看到它与原始输入文件匹配。这是我的例子:

#include <iostream>
#include <fstream>
#include <vector>

// storing each node in a data structure
class Node
{
public:
    Node(char name, char north, char east, char south, char west)
    {
        this->name = name;
        this->north = north;
        this->east = east;
        this->south = south;
        this->west = west;
    };

    char name;
    char north;
    char east;
    char south;
    char west;
};

// function to print out a node
void print_node(Node n)
{
    std::cout << n.name << " " << n.north << " " << n.east << " " << n.south << " " << n.west << " " << std::endl;
}

int main(int argc, const char * argv[])
{
    // first off let's read in our maze data file
    std::ifstream maze_file("maze.dat");

    // create somewhere to store our nodes
    std::vector<Node> nodes;

    // check that we opened the file, then parse each line
    if( maze_file.is_open() )
    {
        while( maze_file.good() )
        {
            // temporary node_data for each line in the file
            std::string node_data;

            // read the current line
            getline( maze_file, node_data );

            // parse the line into tokens (e.g. A, ,*, ,B, ,*, ,* )
            std::vector<char> tokens(node_data.begin(), node_data.end());

            // strip out the blanks ' ' (e.g. A,*,B,*,*)
            tokens.erase( std::remove(tokens.begin(), tokens.end(), ' '), tokens.end() );

            // there should be 5 tokens for a node description
            if( tokens.size() == 5 )
            {
                Node node( tokens[0], tokens[1], tokens[2], tokens[3], tokens[4] );
                nodes.push_back(node);
            }
            else
                std::cout << "There weren't 5 tokens in the node description, there were: " << tokens.size() << std::endl;
        }

        // clean-up the open file handle
        maze_file.close();
    }
    else
        std::cout << "Unable to open file maze.dat";

    // now we can prove that we've stored the nodes in the same way as they were in the file
    // let's print them out from the vector of nodes
    std::for_each(nodes.begin(), nodes.end(), print_node);

    return 0;
}

这是一种将文件转换为数据结构的非常简单的方法。这对于加载文件很有用,然后您可以创建一种保存地图的方法,从而构建一个地图创建程序。

在实际游戏中实际使用迷宫地图时,这可能没有多大帮助。根据您是否要向北、向东、向南、向西旅行,您更有可能想要检索相关房间。为此,您将需要使用 Str1101 先前描述的 std::map 构建图形数据结构

于 2013-07-26T13:51:35.597 回答
0

对您来说很困难的一件事是您不能直接创建节点,因为在早期您需要获取指向尚未创建的节点的指针。使这个问题没有实际意义的一种方法是您似乎正在做的事情:存储节点字母而不是指针:

#include <iostream>
class Maze; // Holds all the nodes; defined later.

class Node
{public:
    static const char kNoLink = '*';
    Node(): north(kNoLink), east(kNoLink), south(kNoLink), west(kNoLink) {}
private:
    char name;
    char north;
    char east;
    char south;
    char west;
    friend std::istream& operator>>(std::istream&, Node&);
    friend std::ostream& operator<<(std::ostream&, const Node&);
    friend class Maze;
};

std::istream& operator>>(std::istream& is, Node& node)
{
    return is >> node.name >> node.north >> node.east >> node.south >> node.west; 
}

std::ostream& operator<<(std::ostream& os, const Node& node)
{
    return os << node.name << ' ' << node.north << ' ' << node.east << ' ' 
        << node.south << ' ' << node.west << '\n'; 
}

然后Maze班级将所有内容都包含在内:

#include <map>

class Maze
{public:
    Maze() {}
    ~Maze();
    Node* GetNode(char name)
    {
        NodeMap::iterator ni = nodeMap.find(name);
        return ni == nodeMap.end()? 0: *ni;
    }
    Node* GoNorth(Node* start) { return GetNode(start->north); }
    Node* GoEast(Node* start) { return GetNode(start->east); }
    Node* GoSouth(Node* start) { return GetNode(start->south); }
    Node* GoWest(Node* start) { return GetNode(start->west); }
private:
    typedef std::map<char, Node*> NodeMap;
    NodeMap nodeMap;
    friend std::istream& operator>>(std::istream&, Maze&);
    friend std::ostream& operator<<(std::ostream&, const Maze&);
};

Maze::~Maze()
{
    // While the map itself will get properly destroyed, its contents won't.
    // So we have to delete the nodes in the map ourselves.
    // For std::map, i->first is the key and i->second is the value.
    for(NodeMap::iterator i = nodeMap.begin(); i != nodeMap.end(); ++i)
        delete i->second;
}

std::istream& operator>>(std::istream& is, Maze& maze)
{
    while(is)
    {
        Node* newNode = new Node;
        is >> newNode;
        maze.nodeMap[newNode.name] = newNode;
    }
    return is;
}

std::ostream& operator<<(std::ostream& os, const Maze& maze)
{
    for(NodeMap::const_iterator i = nodeMap.begin(); i != nodeMap.end(); ++i)
        os << *(i->second);
    return os;
}

现在阅读迷宫很简单:

Maze maze;
build >> maze;

打印它是这样的:

cout << maze;

这里可以进行很多改进,例如将指针直接存储在节点中(这需要两次阅读器:您仍然必须存储字母,然后在阅读整个迷宫后链接所有节点)并删除节点和节点映射上的名称并将所有代码放入 Node 类(允许您从任何节点管理整个迷宫;节点名称在读取迷宫后被丢弃并在打印时重新生成)。

另外,我假设您没有使用 C++11。如果是,那么您可以进一步简化代码。例如,这个:

    for(NodeMap::const_iterator i = nodeMap.begin(); i != nodeMap.end(); ++i)
        os << *(i->second);

变成:

    for(auto i: nodeMap)
        os << *(i->second);

总而言之,有比 istreams 更强大的解析选项。如果您认为编写 Backus-Naur 形式 (BNF) 没什么大不了的,并且想看看在 C++ 中使用运算符重载可以做哪些疯狂的事情,请查看 Boost::Spirit。

于 2013-07-25T01:43:52.523 回答
0
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>

struct node
{
    char name;
    char north;
    char east;
    char south;
    char west;
}; 

std::istream& operator >> (std::istream& is, node& n)
{
    is >> n.name >> n.north >> n.east >> n.south >> n.west;
    return is;
}

std::ostream& operator << (std::ostream& os, const node& n)
{
    os << n.name << ' ' << n.north << ' ' << n.east << ' ' << n.south << ' ' << n.west;
    return os;
}

int main(int argc, char* argv[])
{
    std::vector<node> nodes;

    node n;

    while(std::cin >> n)
      nodes.push_back(n);

    std::copy(nodes.begin(), nodes.end(), std::ostream_iterator<node>(std::cout,"\n"));
    return 0;
}

$ cat nodes.txt | ./a.out 
A * B * *
B * C * A
C G D * B
D * * * C
E I F * *
F J G * E
G * H C F
H * * * G
I * * E *
J * K F *
K * L * J
L * * * K
于 2013-07-25T04:25:31.777 回答