nsnake
Classic snake game for the terminal
Loading...
Searching...
No Matches
BoardParser.cpp
1#include <Game/BoardParser.hpp>
2#include <Config/Globals.hpp>
3#include <Config/INI.hpp>
4#include <Misc/Utils.hpp>
5
6#include <fstream>
7#include <vector>
8#include <string>
9
10// HACK This will be initialized at `Globals::init()`
11std::string BoardParser::directory = "";
12
13std::string BoardParser::extension = "nsnake";
14
15
16
17
18Board* BoardParser::load(std::string name)
19{
20 std::string filename = (BoardParser::directory +
21 name +
22 "." +
24
25 return BoardParser::loadFile(filename);
26}
27
28Board* BoardParser::loadFile(std::string filename)
29{
30 std::ifstream file(filename.c_str());
31
32 if (!(file.is_open()))
33 throw BoardParserException("Can't open file '" + filename + "'");
34
35 // Tells what's the current line on the file
36 // (independent of comments and empty lines)
37 int line_count = 0;
38
39 // The whole file has two parts: metadata and level definition.
40 //
41 // Let's read the whole file, line by line, adding the respective
42 // parts to each of these buffers.
43 //
44 // We'll handle them separately later.
45 std::string metadata_buffer;
46 std::string level_buffer;
47
48 // This will get used to the end of the
49 // function.
50 std::string current_line = "";
51
52 while (std::getline(file, current_line))
53 {
54 ++line_count;
55
56 current_line = Utils::String::trim(current_line);
57
58 // We only care for the line that tells a level
59 // definition will start.
60 if (current_line != "start")
61 metadata_buffer += (current_line + '\n');
62
63 else
64 {
65 // Yay, start of the level definition!
66 bool parsed_level = false;
67
68 while (std::getline(file, current_line))
69 {
70 ++line_count;
71
72 current_line = Utils::String::trim(current_line);
73
74 if (current_line == "end")
75 {
76 parsed_level = true;
77 break;
78 }
79
80 level_buffer += (current_line + '\n');
81 }
82
83 if (! parsed_level)
84 {
85 // End-of-file...
86 // Something wrong happened
88 "Abrupt ending of file while parsing level at line " +
89 Utils::String::toString(line_count)
90 );
91 }
92 // Finished parsing the level!
93 // Back to the metadata.
94 }
95 }
96
97 // Now we'll analyze the level definition we just got from the file
98
99 int player_start_x = 1; // It's (1, 1) because if it somehow starts
100 int player_start_y = 1; // at (0, 0) it will always end up in a wall
101 // and die right at the beginning
102
103 // Finally, when we read the level we have
104 // two states for each tile - "wall" or "not wall"
105 std::vector<std::vector<bool> > rawBoard;
106
107
108 std::vector<std::string> level_lines = Utils::String::split(level_buffer, '\n');
109
110 for (size_t j = 0; j < (level_lines.size()); j++)
111 {
112 current_line = level_lines[j];
113
114 if (current_line.empty())
115 continue;
116
117 std::vector<bool> rawBoardLine;
118
119 // And now we go through each char on the line
120 // checking if it's a wall, blank space or the
121 // player's starting point.
122 //
123 for (size_t i = 0; i < current_line.size(); i++)
124 {
125 if (current_line[i] == SNAKE_CHAR)
126 {
127 player_start_x = i;
128 player_start_y = rawBoard.size();
129
130 // It IS an empty space, after all...
131 rawBoardLine.push_back(false);
132 }
133 else
134 rawBoardLine.push_back(current_line[i] == WALL_CHAR);
135 }
136
137 // Commit this line to the level
138 rawBoard.push_back(rawBoardLine);
139 }
140
141 // I know it's counter-intuitive, but the width
142 // and height is just like this
143 int board_width = rawBoard[0].size();
144 int board_height = rawBoard.size();
145
146 Board* board = new Board(board_width,
147 board_height,
148 ((Globals::Game::teleport) ?
149 Board::TELEPORT :
150 Board::SOLID));
151
152 board->setBoard(rawBoard);
153
154 board->setStartX(player_start_x);
155 board->setStartY(player_start_y);
156
157 // Remember that metadata up there?
158 // Let's get every present metadata through an INI parser
159 std::stringstream stream;
160 stream << metadata_buffer;
161 INI::Parser parser(stream);
162
163 board->setMetadata("name", parser["name"]);
164 board->setMetadata("author", parser["author"]);
165 board->setMetadata("date", parser["date"]);
166 board->setMetadata("comment", parser["comment"]);
167
168 return board;
169}
170std::vector<std::string> BoardParser::listLevels()
171{
172 std::vector<std::string> levels = Utils::File::ls(BoardParser::directory);
173
174 // Remove files that doesn't end with the default file extension
175 //
176 // Also, don't store the full path, only it's basename
177 // (like "file" and not "/path/to/file")
178 //
179 for (std::vector<std::string>::iterator it = levels.begin();
180 it != levels.end();
181 ++it)
182 {
185
186 else
187 {
188 // When we remove an element of a vector
189 // it points to the next element.
190 it = levels.erase(it);
191
192 // We need to decrement it because the `for`
193 // will increment at the end
194 --it;
195 }
196 }
197
198 return levels;
199}
200
Custom exception class to specify an error that occurred during a level loading.
static Board * loadFile(std::string filename)
Loads and parses the level at filename.
static std::string directory
Default directory where the level files are.
static std::vector< std::string > listLevels()
Lists all levels found by the game.
static Board * load(std::string filename)
Loads and parses level with name.
static std::string extension
Default extension for nSnake level files.
A level where the snake runs and eats fruits.
Definition Board.hpp:33
void setMetadata(std::string name, std::string value)
Sets a meta information from this level.
Definition Board.cpp:165
void setBoard(std::vector< std::vector< bool > > &newBoard)
Sets the whole level content.
Definition Board.cpp:139
Loads, reads and parses the contents of an INI file (or string).
Definition INI.hpp:157
std::vector< std::string > ls(std::string path)
Lists all files withing #path.
Definition Utils.cpp:201
std::string basename(std::string path)
Returns the component of a pathname (file name and extension).
Definition Utils.cpp:263
std::string extension(std::string path)
Returns the extension of a file.
Definition Utils.cpp:294
std::string dropExtension(std::string path)
Returns the filename without it's extension.
Definition Utils.cpp:305