Sign in to follow this  
elmepo

Probably a basic question

Recommended Posts

elmepo    123
Hey there, At the moment I'm trying to create a simple roguelike game using the cmd (Not my choice, Our teacher told us to use it) Anyway, I'm having trouble with it. I was wondering if someone could tell me how to read the text in a text file, and output it to the cmd exactly as it's shown in the text file, and then, when a button is pressed (Say W) then I can change the players position on the map.
eg:
The program reads a text file and outputs
######
# #
#@ #
######
When the player types 'W' (Which I already know how to do, I'm using PdCurses)
The Current display is wiped off and replaced with
######
#@ #
# #
######

Share this post


Link to post
Share on other sites
the_edd    2109
In C, you can use functions such as fopen, fclose, fgetc, fread and fgets to open and read files. In C++, the std::ifstream class will do similar things.

If you're using another language further help could be provided, but note that it's frowned upon around here (quite rightly, IMHO) to give too much help with homework and assignments. If you were having an issue with the particulars of some specific thing such as the syntax of a looping construct or the correct use of a function, that would more likely be ok.

Share this post


Link to post
Share on other sites
XDaWNeDX    113
#include <fstream>
#include <iostream>

I have created a full text based tile based game using just these two headers.


And then of course


[url="http://www.google.com/search?btnG=1&pws=0&q=read%2Fwrite+files+%3Cfstream%3E+c%2B%2B"]http://www.google.com/search?btnG=1&pws=0&q=read%2Fwrite+files+%3Cfstream%3E+c%2B%2B[/url]

If your using anything else, just google for that language.

Share this post


Link to post
Share on other sites
elmepo    123
<FONT color=#000000 size=2>Hey, Thanks for the help, I've managed to get fstream working as far as I know, in that it can read the file, but now I need to print it, the only problem being is that I need it to be in const char * format in order to print it to the screen. Any chance you guys could show me how to convert an fstream value into a const char * value? Thanks. Also, before I forget, heres the source code.</FONT>

Share this post


Link to post
Share on other sites
Fabbo    102
[url="http://www.cplusplus.com/doc/tutorial/files/"]This[/url] schould help you with your streams.

There are examples how to print text in a console.

Share this post


Link to post
Share on other sites
rip-off    10976
Why do you need it in a const char * format to print it? You haven't posted your code.

What you probably want to do is create an array representing the map, populate it once from a file and write that to the screen every "frame".

Share this post


Link to post
Share on other sites
the_edd    2109
[quote name='elmepo' timestamp='1307492982' post='4820745']
Hey, Thanks for the help, I've managed to get fstream working as far as I know, in that it can read the file, but now I need to print it, the only problem being is that I need it to be in const char * format in order to print it to the screen.
[/quote]
The first program in any C++ tutorial will show you how to print characters to "the screen" via std::cout. Using std::cout, which is itself an ostream, you can write a multitude of objects to the console, including numerical primitives, std::strings and const char *s.

[quote]
Any chance you guys could show me how to convert an fstream value into a const char * value?
[/quote]
This question doesn't really make sense. An fstream is an object that is used to read and/or write data between a file and C++ objects. Are you wanting to read data [i]from[/i] an fstream in to one or more C++ objects, or write text-based representations of objects [i]to[/i] an fstream?

Share this post


Link to post
Share on other sites
elmepo    123
I need it as a const char* because I'm using PDCurses, and all variations of printw require the outputted statement to be in that format. I'm not using std::cout because as far as I knew, it could only print along one line, and without any options to place it physcially in the cmd, which I'll likely need, and it's the reason I'm using pdcurses. I'm not sure about the fstream question. When I tried to compile a version, visual studio 2010 replied with the error message along the lines of "error C2440: 'initializing' : cannot convert from 'std::fstream' to 'const char *' Heres the code <BR>[code]#include "stdafx.h"<BR> #include<BR> <CURSES.H>#include <BR><STDLIB.H>#include<BR> <FSTREAM>#include <BR><IOSTREAM>using namespace std;<BR> static void main(int argc, char *argv[])<BR> { <BR>initscr(); <BR>fstream level; <BR>level.open ("level.txt" //I've placed the text file in the directory, so it can read it without adding C:\<BR> const char *p = level; <BR>printf(p);<BR> refresh(); <BR>getch();<BR> endwin();<BR> }[/code]

Share this post


Link to post
Share on other sites
rip-off    10976
The compiler is correct, a std::fstream isn't a const char *, and it knowns of no implicit conversion. You should use one of std::fstream's member functions to read the characters into a buffer (e.g. std::string or std::vector<char>).

[quote]
I need it as a const char* because I'm using PDCurses, and all variations of printw require the outputted statement to be in that format.
[/quote]
That is OK. Remember you can get a const char pointer from a std::string by using its c_str() member function.

Share this post


Link to post
Share on other sites
elmepo    123
Awesome, Thanks, It seems to be working so far, at least with cout, although I've got a problem.With at the moment I've got two iterations of the program, one using cout, and one where I'm attempting to use c_str. When I attempt to use cout, it outputs only a single line, even if I add a breakline that would normally be interpreted by the compiler and completely ignored like /n. I'm trying to work out c_str, but I don't know how to access it. How do I use it to convert the fstream value to string? If I try to call it with the argument level, it says that it's unidentified, even when I'm using fstream and string includes. Could you guys sheed some light on this? Thanks.

Here are the two different source codes, although Ones commented out because I'm too lazy to go through another new project and add all the different linkers and the like.

[code]// reading a text file
/*#include <iostream>
#include <fstream>
#include <string>
#include <curses.h>
using namespace std;

int main () {
string line;
initscr();
ifstream myfile ("level.txt");
if (myfile.is_open())
{
while ( myfile.good() )
{
getline (myfile,line);
cout << line << endl;
system("pause");
//getch();
}
myfile.close();
}

else cout << "Unable to open file";

return 0;
}*/

//#include "stdafx.h"
#include <CURSES.H>
#include <STDLIB.H>
#include <FSTREAM>
#include <IOSTREAM>
#include <string>
using namespace std;
static void main(int argc, char *argv[])
{
initscr();
fstream level;
level.open ("level.txt");
c_str(level
printf(p);
refresh();
getch();
endwin();
}
[/code]

And heres the test level I'm using just in case you also needed it.
[code]

#####/n
# #/n
# @ #/n
# #/n
#####/n
[/code]

Share this post


Link to post
Share on other sites
rip-off    10976
You don't need to use character escape codes in data files. When you're reading from a file, the newline characters are already there. You'd need to write extra code if you wanted to support escape characters in data files - the runtime does not provide this for you.

Newline escapes are only necessary when you're embedding a newline into a string literal. If string literals could span multiple lines, you wouldn't need to use them (though you might to keep the code readable. In any case, the escape character is \, so if you were embedding in a string literal you use \n not /n.

Please include standard headers in lowercase. It makes your code non-portable to use uppercase like you are doing. In C++, we include the C standard headers by using <cstdlib> rather than <stdlib.h>.

Ok, on to the task at hand. Your first program was probably correct. The second one tries to call a global function called c_str() on a std::fstream object. This is not what I said. I said that if you have a std::string object, you can call its member function c_str() to return a const character pointer of the strings data.

Here is a more complete example:
[code]
#include <string>
#include <fstream>
#include <vector>

#include "fictional/console.h"

typedef std::vector<std::string> Level;

Level loadLevel(const std::string &file)
{
std::ifstream in(file.c_str());
std::string line;
Level result;
while(std::getline(in, line))
{
result.push_back(line);
}
return result;
}

void processInput(Level &level);

void update(Level &level);

void draw(const Level &level)
{
console::clearScreen();
for(unsigned i = 0 ; i < level.size() ; ++i)
{
console::moveCursorToLine(i);

const std::string &line = level[i];

// This is an example of a function expecting const char *
console::outputString(line.c_str());
}
}

int main()
{
std::vector<std::string> level = loadLevel("level.txt");

while(running)
{
processInput(level);
update(level);
draw(level);
}
}
[/code]
I'm using a fictional console library to demonstrate the kind of calls you might need to draw the map. You'll need to rewrite the routine to use the curses functions.

Share this post


Link to post
Share on other sites
elmepo    123
Hey, I ran the program, and while it works, instead of getting
[code]

#####
# #
# @ #
# #
#####[/code]

I get
[code]

#####
# #
# @ #
# #
#####[/code]

Do you have any idea why this could be happening.

Heres the code with the curses added.

[code]#include <string>
#include <fstream>
#include <vector>
#include <curses.h>

typedef std::vector<std::string> Level;

Level loadLevel(const std::string &file)
{
std::ifstream in(file.c_str());
std::string line;
Level result;
while(std::getline(in, line))
{
result.push_back(line);
}
return result;
}

void processInput(Level &level);

void update(Level &level);

void draw(const Level &level)
{
initscr();
refresh();
for(unsigned i = 0; i < level.size() ; ++i)
{
move(i, i);

const std::string &line = level[i];
printw(line.c_str());
}
getch();
endwin();
}

int main()
{
std::vector<std::string> level = loadLevel("level.txt");

draw(level);
}[/code]

Share this post


Link to post
Share on other sites
rip-off    10976
I imagine it is to do with how you position the cursor. You're calling move(i,i) - which is causing the triangular shape you're seeing. Convince yourself of this. The solution should be obvious once you see why it is happening.

Share this post


Link to post
Share on other sites
elmepo    123
Thanks, I kicked myself when I noticed it :). Is there any chance you could give me help on how to move the player and refresh the cmd, so that it gets rid of the previous map and replaces it. I'm guessing I'd use fstream to open and write the new map with the new positions etcetera, but How would I go about changing the display and getting the player input. I'm a little unsure about this, since I'm used to using C# and XNA, where input was included, but I think we C++ I have to use ASCII Code don't I?

I'm trying at the moment to read the input from the player, by simply reading if the 'w' key has been pressed, but I can't seem to get the program to read the input without closing, which might be because of the getch(); line, which is used to wait for a character to be pressed.

heres the updated code.

[code]#include "stdafx.h"
#include <string>
#include <fstream>
#include <vector>
#include <curses.h>
#include <stdio.h>
#include <iostream>

typedef std::vector<std::string> Level;

Level loadLevel(const std::string &file)
{
std::ifstream in(file.c_str());
std::string line;
Level result;
while(std::getline(in, line))
{
result.push_back(line);
}
return result;
}

void processInput(Level &level);

void update(Level &level);

void draw(const Level &level)
{
initscr();
refresh();
for(unsigned i = 0; i < level.size() ; ++i)
{
move(i, 0);
const std::string &line = level[i];
printw(line.c_str());
}
//getch();
//endwin();
}

int main()
{
char *buffer = "Any Character stream";
int capa, lettera, nota;
char c;
capa = lettera = nota = 0;

std::vector<std::string> level = loadLevel("level.txt");

draw(level);

switch ( c )
{
case 'w':
printw("You have pressed w");
break;

}
//std::cin.ignore();
//std::cin.get();
getch();
//endwin();
}[/code]

Share this post


Link to post
Share on other sites
rip-off    10976
[quote]
I'm guessing I'd use fstream to open and write the new map with the new positions
[/quote]
Generally you wouldn't want to do this. Reading from the disk is expensive, and in this case unnecessary as you have the data in memory.

The simplest solution is to locate the player character '@' in the level array, and if they're trying to move onto a "space" character then swap the two locations. If not, there is a collision and you ignore the move request.

[quote]
I'm a little unsure about this, since I'm used to using C# and XNA, where input was included, but I think we C++ I have to use ASCII Code don't I?
[/quote]
No. You can use any of the input API's the operating system provides in C++. But from the console I'm not sure how far your options extend. Certainly using functions like kbhit() and getch() (possibly from <conio.h>) would be the simplest solution for the moment, and will work for standard WASD controls. Curses probably has equivalent functions too (I've never used it).

[quote]
I'm trying at the moment to read the input from the player, by simply reading if the 'w' key has been pressed, but I can't seem to get the program to read the input without closing, which might be because of the getch(); line, which is used to wait for a character to be pressed.
[/quote]
There is no loop in your program to keep it open. If you look at my sample program I included a basic "game loop". You are testing "c" without ever setting it to a value - consider increasing your compiler warning level (and tell it to treat warnings as errors) until the code no longer compiles. This kind of mistake can cause bugs. I'm also wary of your "buffer" variable. It isn't used yet, but you shouldn't be using a string literal as a buffer. String literals are often placed in read only memory, which can cause access violations if you try to write to them.

Finally, I notice you are passing the raw string you read in from a file to printw(). The first argument expected is a printf format string, so I'd recommend you do not pass the raw string directly. If the map file contained any format specifiers, the result could be unpredictable and could cause your program to crash.

Instead, use printw("%s", line.c_str()). Generally you have to be careful with data that comes from an untrusted source (yes, the filesystem is untrusted!). For a small application like a game there isn't a huge risk, but if you ever write something available over the network this is the kind of thing an exploiting hacker would love.

Share this post


Link to post
Share on other sites
elmepo    123
Hey there, How do I keep the game open and draw the level. At the moment I've tried do until, and while loops, and an if then statement modified to be a loop, both with and without the draw(level); inside, but if I have the draw(level); outside the loop, it is never drawn, and inside the loop it stops any input from being read. Also, How to I change player input into a variable, So I can make c's value to be the sma evalue as the player's input.
EDIT: Ignore that, I was misreading parts of the code and I've corrected that, Could you now help me with searching the array? I'm guessing I'll need to use a binary search, because a sequential sort would take waaay too long for some of the levels, but i'm not exactly sure on how to 'switch' the two characters.

Share this post


Link to post
Share on other sites
rip-off    10976
Binary search only makes sense on sorted data. Your map isn't sorted, so you cannot use a binary search. A sequential search would probably be lightning fast for the size of levels you're probably dealing with, unless you're making a text based World of Warcraft or something!

The simplest solution is to track the player's position by noting the position when the map is loaded (1 search), and then just keeping those (x,y) indices for later use. When the player presses the movement keys, calculate newx and newy. If map[newy][newx] is passable, then you restore the tile under the player's feet (map[y][x]), copy the tile at map[newy][newx] to a buffer tile and replace the tile with the player.

The easiest way to do that is to "swap" the buffer and player's current position, and then swap the player's new position and the buffer. The buffer tile will need to have some neutral tile type such as "grass" to start with.

The function std::swap() from <algorithm> is a good way to swap two values.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this