I'm writing a simple 2D game in C++ (a language that is still quite new to me) using DirectX that involves a grid of 26x26 tiles sorted in a Cartesian-like manner - with the origin being the top leftmost space at 0,0. Each tile needs to contain the values:
int tileX (from 0 to 25)
int tileY (from 0 to 25)
int tileType (0 is empty)
int tileState
These values will be stored in a text file stage_n.txt (228 lines long) which is formatted like the following:
2 2 1
3 2 1
6 2 1
7 2 1
10 2 1
11 2 1
...
Each set of tile values are separated by a new line, while each value is separated by a space. The first value is tileX, the second value is tileY, the third value is tileType. All tiles are initially assumed to have a tileState of 8.
These values will be looped through to draw the stage at the start of the game, and will be changed often in the code.Note that only tiles that are occupied are listed in the file. Tiles that are empty are not listed.
My first thought was to use a multidimensional array tileMap[25][25][1] like the following:
tileMap[0] = 0 (X value) // All tiles on line X0
tileMap[0][0] = 0 (Y value) // First tile on line 0 (at Y0)
tileMap [0][0][0] // Tile type
tileMap [0][0][1] // Tile state
tileMap[0][1] = 1 (Y value) // Second tile on line 0 (at Y1)
tileMap [0][1][0] // Tile type
tileMap [0][1][1] // Tile state
... through to 25 (the last tile on line 0)
tileMap[1] = 1 (X value) // All tiles on line X1
tileMap[1][0] = 0 (Y value)
...
tileMap[1][0] = 1 (Y value)
...
...
... through to 25 (the last line)
But I was also considering using a structure:
struct tileData{
int tileX;
int tileY;
int tileType;
int tileState;
} tile[676]; // 676 is the total amount of tiles.
Going back to my question; in this situation, would it be more efficient to use a struct or an array? How would I go about initializing/filling the easier option using data in the above text file? I've tried to imitate many examples online (that have used ifstream), but none of them have seemed to work.
This question has probably been answered a lot, but I just can't get my head around how to do it. I hope this makes enough sense. Thanks!
EDIT: Additionally, where should I place my text file if I'm using VS2013?
I doubt there would be any different in performance, since both accessing an array and accessing a member of a struct just involve accessing some baked-in offset from some address. If it really matters because you've discovered this code to be a bottleneck, then you'll need to do some performance measures. I can almost guarantee that the compiled code will be identical in either case.
Anyway, it looks to me like it would be most appropriate to use a struct. While all the members of the struct are the same type, they do not have the same meaning. It's certainly possible that they could have different types. A struct nicely groups together these different yet related values.
Reading into your 1D array should be as simple as:
std::ifstream file("stage_n.txt");
int i = 0;
while (file >> tile[i].tileX
>> tile[i].tileY
>> tile[i].tileType) {
tile[i].tileState = 0;
++i;
}
There's no reason you can't have a 2D array of structs, though. That would better represent your grid. In that case, you would just need to keep track of an x and y position as you read from the file (instead of i).
The file reading code above doesn't do much in the way of error checking. If you want to be precise, you should consider what exactly should be valid. For example, the above code would still accept the data even if it were all on one line. If you want to read the file on a line-by-line basis, you'll need to use std::getline and then parse each line.
i would use a 2d array of Tile objects (or std::vector or std::array, always preferred to naked arrays)
struct Tile
{
int tileType;
int tileState;
}
Tile grid[25][25];
dont put the X/Y of the tile in the struct. This knowledge is implicitly encoded in its position in the array
I think there is no difference in performance between an array and a struct. But there is a difference in better code - use the struct tilData and write a istream-operator for it.
std::istream& operator>>( std::istream& in, tileData& td )
{
if( in >> td.tileX >> td.tileY >> td.tileType )
td.tileState = 8;
return in;
}
You can read it in this way:
size_t n = 0;
for( ; file >> tile[n]; ++n )
;
if( file.eof() ) // check whether End Of File is reached
{
cout << "Ok " << n << "Tiles read\n";
}
Related
I am currently trying to solve this kattis problem in C++:
Ecape Wall Maria
Wall Maria has been broken! Eren must evacuate as soon as possible from his house. He must find the fastest route to escape within Wall Maria before the titans rush in. Wall Maria is represented as a N×M grid in which Eren can move horizontally or vertically.
There are burning houses and buildings which prevent Eren from passing through them. The burning houses and buildings are represented as ‘1’. Unburned or safe areas are represented as ‘0’. There are some areas which can be entered but only from a specific direction. These areas can be represented by either ‘U’, ‘D’, ‘L’, or ‘R’. For example, if there is an ‘R’ that means that area can only be entered from the right neighboring tile within Wall Maria’s grid. Similarly, ‘U’ tiles can only be entered from above, ‘D’ tiles can only be entered from below, and ‘L’ tiles can only be entered from the left.
Eren knows the time t at which the titans will rush in. It takes 1 unit of time to traverse 1 zone (which corresponds to 1 tile in the grid). Once he reaches any border of Wall Maria he is safe.
Eren’s starting position is represented by the letter ‘S’. If Eren escapes at or before time t, he is safe. Given his position within Wall Maria determine if it is possible to escape. If it is possible determine the number of zones that must be traversed to lead to the quickest escape.
Input
The input consists of a single test case. The first line contains three integers t (1≤t≤200) , N (1≤N≤100) and M (1≤M≤100). The rest of N lines will be Wall Maria’s grid containing characters ‘1‘, ‘0‘, ‘S‘, ‘U‘, ‘D‘, ‘L‘, or ‘R‘. There is exactly one ‘S‘ in the input.
Output
If it is possible to escape Wall Maria, output the minimum number of zones that must be traversed to escape. If it is not possible to escape, print “NOT POSSIBLE”!
I am having some issues with finding the character "S" in the matrix on input.
I am thinking that once we have the input of the matrix, we find the character "S" and then look to the right, left, up and down of that character. If the character is not = 1 then you repeat the process from that character until you have "left" the matrix.
However, I have tried writing code to look for the starting point (the character "S) but I have been unsuccessful in doing that.
Furthermore, I am not sure how to look around the character once I have found it. I have only gotten to the point where I can accept input, not much further. Help would be appreciated
This is my code so far:
int main(){
int M;
int N;
int t;
string wall;
cin >> t >> N >> M;
//Takes the matrix input
for (int i = 0; i < N; i++)
{
cin >> wall;
}
}
The two steps are:
Decide what data structure you want to use to represent the grid you're about to traverse. std::vector<std::string> is a standard choice here.
Read the grid into the vector line by line, storing the row and column for 'S' as you go.
Here's one approach:
#include <iostream>
#include <string>
#include <vector>
int main() {
int M;
int N;
int t;
int sx = 0;
int sy = 0;
std::cin >> t >> N >> M;
std::vector<std::string> grid(N);
for (int i = 0; i < N; i++) {
std::cin >> grid[i];
size_t pos = grid[i].find("S");
if (pos != std::string::npos) {
sx = pos;
sy = i;
}
}
// show the position; remove when you're ready to solve the problem
std::cout << sx << ", " << sy << "\n";
}
Here's the output on two of the samples:
$ ./a
1 4 4
1S01
1001
1011
0U11
1, 0
$ ./a
2 4 4
1111
1S01
1011
0U11
1, 1
I am using the following function written in C++, whose purpose is to take the integral of one array of data (y) with respect to another (x)
// Define function to perform numerical integration by the trapezoidal rule
double trapz (double xptr[], double yptr[], int Npoints)
{
// The trapzDiagFile object and associated output file are how I monitor what data the for loop actually sees.
std::ofstream trapzDiagFile;
trapzDiagFile.open("trapzDiagFile.txt",std::ofstream::out | std::ofstream::trunc);
double buffer = 0.0;
for (int n = 0; n < (Npoints - 1); n++)
{
buffer += 0.5 * (yptr[n+1] + yptr[n]) * (xptr[n+1] - xptr[n]);
trapzDiagFile << xptr[n] << "," << yptr[n] << std::endl;
}
trapzDiagFile.close();
return buffer;
}
I validated this function for the simple case where x contains 100 uniformly spaced points from 0 to 1, and y = x^2, and it returned 0.33334, as it should.
But when I use it for a different data set, it returns -3.431, which makes absolutely no sense. If you look in the attached image file, the integral I am referring to is the area under the curve between the dashed vertical lines.
It's definitely a positive number.
Moreover, I used the native trapz command in MATLAB on the same set of numbers and that returned 1.4376.
In addition, I translated the above C++ trapz function into MATLAB, line for line as closely as possible, and again got 1.4376.
I feel like there's something C++ related I'm not seeing here. If it is relevant, I am using minGW-w64.
Apologies for the vagueness of this post. If I knew more about what kind of issue I am seeing, it would be easier to be concise about it.
Plot of the dataset for which the trapz function (my homemade C++ version) returns -3.431:
Please check the value of xptr[Npoints - 1]. It may be less than xptr[Npoints - 2], and was not included in the values that you output.
I'm trying to create a simulation in which I have objects moving within a rectangular grid. Information is given in the form of a text file. Sample input is as follows:
5 5
0 1 N
PFPFFSF
2 3 S
FSFFSFFSPF
First line is the dimension of the grid (in this case 5 x 5 assuming the bottom left coordinate is 0,0)
The rest of the input is just info in regards to the object and how it moves. Each object has 2 lines of input. First line is it's starting coordinates and orientation while the second line describes its movements.
When using an input stream, how can I grab the input so that it groups accordingly?
I know for the first line, I can just use
simulationSettings >> x >> y;
to grab the size of the grid.
However, is there a way of grabbing the rest of the input and grouping the info by 2 lines (for each object)?
So, for example, stream the input so that my object1 will have 0 1 N and PFPFFSF while object 2 has 2 3 S and FSFFSFFPF and so on should there be more objects.
If you can simply ignore how the file is actually structured in line, you structure is just:
2 integer values for the grid size
n times (per object):
2 integers for the initial position
one string for the initial direction
one string for the movements
You could just use:
simulationSettings >> x >> y;
if (! simulationSettings.good()) {
// process error condition and exit
}
for(;;) {
int xinit, yinit;
std::string direction, movements;
simulationSettings >> xinit;
if (simulationSettings.eof()) break; // normal end of file
simulationSetting >> yinit >> direction >> movements;
if (! simulationSettings.good()) {
// process error condition and at least break from the loop
}
// process the object
}
I have a .txt file which I'm trying to gather data from, that can then be used within variables within my code to be used in other functions.
Here's an example of my text file:
0 10 a namez 1 0
0 11 b namea 1 1
1 12 c nameb 1 1
2 13 d namec 0 1
3 14 e named 1 1
So my file will not always be the same number of lines, but always the same number of variables per line.
I currently have this, to firstly get the length of the file and then change the amount of rows within the array:
int FileLength()
{
int linecount = 0;
string line;
ifstream WorkingFile("file.txt");
while(getline(WorkingFile, line))
{
++linecount;
}
return linecount;
}
int main()
{
string FileTable [FileLength()][6];
}
Firstly I don't know if the above code is correct or how I can add the values from my file into my FileTable array.
Once I have my FileTable array with all the file data in it, I then want to be able to use this in other functions.
I've been able to do:
if(FileTable[2][0] = 1)
{
cout << "The third name is: " << FileTable[2][3] << endl;
}
I understand my code may not make sense here but I hope it demonstrates what I'm attempting to do.
I have to do this for a larger text file and all the 6 variables per line relate to be input to a function.
Hold each line in its own object, this is much clearer:
struct Entry
{
std::array<std::string, 6> items; // or a vector
};
In main:
std::vector<Entry> file_table( FileLength() );
Note that it is a waste of time to read the whole file first in order to find the number of entries. You could just start with an empty vector, and push in each entry as you read it.
Your access code:
if( file_table.size() > 2 && file_table[2].items[0] == "1" )
{
cout << "The third name is: " << FileTable[2].items[2] << endl;
}
I would actually recommend giving the members of Entry names, instead of just having an array of 6 of them. That would make your code more readable. (Unless you really need to iterate over them, in which case you can use an enum for the indices).
You could define an operator[] overload for Entry if you don't like the .items bit.
since the number of lines is dynamic I suggest to use vector instead of array. you can push back your data to the vector line by line until you read eof.
also try to study about OOP a little , it would make your code more understandable.
take look at these:
http://www.cplusplus.com/reference/vector/vector/
http://www.geeksforgeeks.org/eof-and-feof-in-c/
I'm trying to create a function where it allows the user to type in multiple amounts of integers, so if the user wanted to have 3 different storages that hold different integers, the input would look something like this:
5
97 12 31 2 1 //let's say this is held in variable "a"
1 3 284 3 8 // "b"
2 3 482 3 4 // "c"
2 3 4 2 3 // "d"
99 0 2 3 42 // "e"
Since we don't know what number the user will input every time, I'm not sure how to create a dynamically allocated array that will create an x amount of arrays every time.. I want to be able to access each index of a, b, c, d, e or however many arrays there are.
So far, this is what I have, but I'm having trouble creating the arrays since it's unpredictable. I'm purposely not using vectors because I don't really get how pointers work so I'm trying to play around with it.
int* x;
int length, numbers;
cin >> length;
x = new int[length]
for (int i=0;i<length;i++)
{
std::getline(std::cin, numbers); //this didn't work for me
x[i] = numbers
}
If anything seems unclear, please let me know! Thank you!
It doesn't get the first line. It gets 1 integer at a time and since you have 5 integers per line and you entered 5 in the first line you end up getting only the numbers in the first line. x in your code is an array of integers and it needs to have enough place for all your integers which in this case is 25. If 5 integer per line is guaranteed then you can assume allocating 5 * length integer-long place will work. You will also need an inner for loop. 1 for to loop through lines and another one to loop through every integer on a line.
I would suggest using cin like so:
int d;
while(cin){
cin >> d;
// Do something with d
if(cin.peek() == '\n'){
// Create a new row in your dynamic array
}
}
This will grab each digit up to the space.
Another way to achieve this is by using strings with getline() in conjunction with string.empty() to get each line, then using strtok to split the line up into tokens. Although getline only works on strings, strtok will split the string up into tokens, which you can then cast to an int (or use atoi).
To store these tokens you will want to use a vector, since they are dynamic by nature and can easily be resized to fit any need. I would see this discussion on multi-dimensional vectors.