Link to home
Start Free TrialLog in
Avatar of jmckennon
jmckennon

asked on

Editing text files using fstream

Hi,
I'm writing a text based adventure for my final programming project for a class, and I seem to have hit a bit of a snag. I'm not a very savvy programmer, but I do know alot of the basics. We have alot of freedom with the program, and get graded based on how unique, creative, and the features the program has. I wanted to add in an edit mode to the program, so that if the user types in a certain "code" in the beginning, he/she can edit the text file that contains the game information.

My program reads from a text file, rooms.txt. The file contains the total number of rooms, the room index, name, description, the exit locations, treasure name, treasure description, treasure value, monster name, monster description, monster health, and the information on the sign in the room.

I have an idea of how to do the implementation, but i'm not quite sure about it. I wanted to use fstream and have the program prompt the user for which room they want to edit. I'm not sure how to have the program replace the given lines in the text file, or anything. I'll attach my text file at the end, I hope someone can help me figure out how to implement this.
rooms.txt
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Text files cannot partial updated as texts were streamed with lines of variable length. To update a text file you need to read all file (e. g. into a std::vector<std::string> using getline) make selective updates on one or more lines and finally open the file for write (what truncates it to zero length) and write it again to disk.
Avatar of jmckennon
jmckennon

ASKER

i'm not quite sure what you mean by that. The text file has both integer values and text in it. Should I use a string stream or something of that nature?
>>>> The text file has both integer values and text in it.
Text files should have only text. Integers also could/should be stored as strings.

>>>> i'm not quite sure what you mean by that.
A textfile is a stream of characters where each line wrap was stored as a pair of CRLF (carriage-return and linefeed) characters. These characters are not printable and have ascii code 13 (CR) and 10 (LF).

That is the first line<CRLF>And that is the second line which is longer than the <CRLF>first line. But now we are already on the third line.<CRLF><CRLF>.

If you read that in, all CRLF were turned to a single linefeed  (LF or '\n' in C/C++) and depending on whether you read line for line or char by char you either have an array off lines or an array of chars. If you want to insert a new word somewhere in the second line, all chars following the insert point must be moved (to the right). That is not so difficult in memory but on file it is rather impossible. So, the only practical way to edit a text file which has lines of arbitrary length ist to write a new text file.

Things were different if you write all lines with same length if necessary by padding up with spaces. Then, yi you want to updae a line somewehere you can compute the file position of that line, navigate to the line and make a selective update on one line.

But if you are so far, you better should write a binary file with binary data records. These records can be read in into structures with one read and all members of the structure are directly available without any parsing. However, the structure may not contain pointers or object (class) members cause that would spoil the binary read and write.

I see. I'll attach my main program that I have for the game so far. At this point I really have no idea where to go as far as coding it is concerned. I created a function called editMode, which  will enter the program into edit mode if the user enters "edit mode" as the player's name.

The portion where it says editMode in the main isn't finished, it was just my preliminary idea of how to go about formatting the code for what I'm trying to implement, but the way I was trying won't work the way I have my game written. Any help in how to do this is greatly appreciated.
//Justin McKennon
//ECE264
//Adventure 1 file
 
 
#include <iostream>
#include <fstream>
#include "Treasure.h"
#include "Room.h"
#include <cstdlib>
#include "Thief.h"
#include <ctime>
#include <vector>
#include <string>
#include "Monster.h"
#include "Player.h"
#include "Sign.h"
#include <windows.h>
using namespace std;
 
void futureRoom(Room& Room, Treasure& Treasure, Monster& Monster,Sign& Sign, int& roomIndex, int numOfRooms);
void currentRoom(Room& Room, Treasure& Treasure, Monster& Monster,Sign& Sign, int& roomIndex, ifstream& in1);
void printAll(Room& Room, Treasure& Treasure, Monster& Monster);
int thiefLocation(int& roomIndex, int numOfRooms);
int index(int &roomIndex);
void printPlayer(Player& Player);
int gameEnd(int &roomIndex);
bool editMode(Player& Player);
 
bool editMode(Player& Player)
{
	char n[25];
	string name;
	string name2="edit mode";
 
	Player.getName(n);
	for(int i=0;i<25;i++)
	{
		name=name+n[i];
	}
	if(name==name2)
	{
		return true;
 
	}
	else
		return false;
 
 
 
 
}
 
int gameEnd(int &roomIndex)
{
	int x(0);
	x=roomIndex;
 
	if(x==21)
	{
		return 1;
	}
	else
		return 0;
}
 
 
void printPlayer(Player& Player)
{
	Player.output(cout);
}
 
int index(int &roomIndex)
{
	return roomIndex;
}
 
int thiefLocation(int numOfRooms)
{
	Thief Thief;
	int location(0);
	int ThiefIndex(0);
	srand(time(NULL));
	location= rand() % numOfRooms;
	Thief.setLocation(location);
	ThiefIndex= Thief.getLocation();
	return ThiefIndex;
}
 
void currentRoom(Room& Room, Treasure& Treasure, Monster& Monster,Sign& Sign, int& roomIndex, ifstream& in1) //determines the information of the room the player is currently in
{
	int futureRoom = -1;
	in1.close();
	in1.open("rooms.txt");//opens the file rooms.txt
	in1.ignore(2);//ignores the total number of rooms and roomIndex
 
	in1 >> futureRoom;
	while(futureRoom <= roomIndex)
	{
		in1.ignore(1);//ignores carriage return
		Room.input(in1); //reads in the information for the room
		Treasure.input(in1);//reads in the treasure information
		Monster.input(in1);
		Sign.input(in1);
		in1>>futureRoom;
 
 
	}
}
void futureRoom(Room& Room, Treasure& Treasure, int& roomIndex, int numOfRooms, Monster& Monster, Sign& Sign) //determines the next room based on the user's input
{
 
 
	char direction;
	roomIndex = -1;
 
	while (roomIndex < 0)
	{
		cout<<" Which direction would you like to travel? "<<endl;
 
		cout << ">";
 
 
		cin >> direction;
		//uses the get exit function in room.cpp to determine direction and whether or not it is a valid exit
		switch(direction) {
			case 'n':
			case 'w':
			case 'e':
			case 's':
				roomIndex = Room.getExit(direction);
 
 
 
				if (roomIndex == -1)
					cout << "You can't go that way!" << endl;
				break;
			case 'l':
				Sign.output(cout); //prints the information for the room and treasure
				break;
 
			case 'x':
				roomIndex = numOfRooms;
				return; //exits
 
		}
	}
}
void printAll(Room& Room, Treasure& Treasure, Monster& Monster)
{
 
 
	Room.output(cout); //prints out  the information of the room when cout is passed as argument
	Treasure.output(cout); //prints out treasure information
	Monster.output(cout); 
}
 
 
 
int main()
{
	Room Room; //creates a room class
	Treasure Treasure; //creates a treasure class
	Thief Thief;
	Monster Monster;
	Player Player;
	Sign Sign;
	vector<string> treasureList;
	int thiefIndex(0);
	char choice;
	char title[100];
	char name[100];
	char description[100];
	int value(0);
	char decision;
	int mHealth(0);
	int pHealth(0);
	int pDamage(0);
	int mDamage(0);
	int random(0);
	int victory(-1);
	char copy[20];
	char dropItem;
	int lose(-1);
	char mode;
	int roomEditIndex(0);
	int option(0);
	char newName[40];
	char newDescription[300];
	int newValue(0);
 
 
 
	int numRooms(0);
	int roomIndex(0);
 
	ifstream in1; //creates an input stream named in1
	in1.open("rooms.txt");
	in1 >> numRooms;
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 2);
	cout<<endl<<" Welcome to Alcatraz, enjoy your playing experience"<<endl<<endl<<" A Justin McKennon, Josh LaClair, Adam Houghton, Barry Gaffey and Craig Nathan production"<<endl;
 
	cout<<endl;
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
	Player.input(cin);
	Player.output(cout);
 
	editMode(Player &Player);
	ifstream in1;
	while(editMode)
	{
		cout<<"You have entered the editing portion of this program. "<<endl<<endl;
		cout<<"In this mode, you can edit the characteristics of the rooms supplied in the text file "<<endl
			<<" Keep in mind, this may alter the playing experience and flow of the program."<<endl<<endl;
		cout<<"Which room would you like to edit? Enter -1 if you are finished editing"<<endl;
		cout<<" Room #: "<<endl<<"> ";
		cin>>roomEditIndex;
		while(roomEditIndex!=-1)
		{
			in1.close();
			in1.open("rooms.txt");//opens the file rooms.txt
			in1.ignore(2);//ignores the total number of rooms and roomIndex
			in1>>futureRoom;
 
 
		while(futureRoom <= roomEditIndex)
		{
			in1.ignore(1);//ignores carriage return
			Room.input(in1); //reads in the information for the room
			Treasure.input(in1);//reads in the treasure information
			Monster.input(in1);
			Sign.input(in1);
			in1>>futureRoom;
 
 
		}
		cout<<"Enter the number of the option you would like to edit "<<endl;
		cout<<"1. Room Name "<<endl<<"2. Room Description "<<endl<<" 3. Treasure Name"<<endl<<"4. Treasure Description"<<endl
			<<"5. Treasure Value"<<endl<<"6. Monster Name"<<endl<<"7. Monster Description"<<endl<<"8. Monster Health"<<endl
			<<"9. Sign information"<<endl;
		cin>>option;
		switch(option)
			case 1:
				cout<<"Enter the new Room Name: ";
 
 
 
 
 
 
 
 
 
	while(roomIndex < numRooms)//ensures roomindex is valid
	{
		currentRoom(Room, Treasure,Monster,Sign, roomIndex, in1);
		printAll(Room, Treasure,Monster);
		pHealth=Player.getHealth();
		mHealth=Monster.getHealth();
		pDamage=pHealth/5;
		mDamage= mHealth/5;
 
		cout<<endl<<" You enter cautiously. Are you going to sneak over to the treasure? " <<endl<< " >";
		cin>>choice;
 
		if(choice=='y')
		{
			if(victory==-1)
			{
				cout<< " You have been spotted!"<<endl;
				cout<<" What would you like to do?"<<endl<<">";
				while(victory==-1 &&lose==-1)
				{
					cin>> decision;
 
					while(decision=='a' &&victory==-1)
					{
 
 
						srand(time(NULL));
						random=rand() %5;
						if (random > 3)
						{ cout<< " You swing violently but miss "<<endl;
						cout<<"You have been hit for "<< mDamage <<" damage"<<endl;
						pHealth=pHealth-mDamage;
						cout<<" What would you like to do?"<<endl<<">";
						cin>> decision;
						}
 
						if (random <= 3)
						{
							SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 5);
							cout<< "You strike the enemy dealing "<< pDamage << " damage"<<endl;
							mHealth=mHealth-pDamage;
							SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
 
						}
 
						if(mHealth <=0)
						{
							SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 5);
							cout<<" You have struck down the enemy. "<<endl;
							pHealth= pHealth+(mDamage*2);
							victory=1;
							SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
 
						}
						srand(time(NULL));
						random=rand() %5;
 
						if(mHealth>0 && random<=3)
						{
							SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 5);
							cout<<"You have been hit for "<< mDamage <<" damage"<<endl;
							pHealth=pHealth-mDamage;
							cout<<"You currently have "<< pHealth<<" hp"<<endl;
							cout<<" What would you like to do?"<<endl<<">";
							cin>> decision;
							SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
						}
						if(mHealth>0 && random >3)
						{
							cout<<" The enemy has missed you!"<<endl;
						}
						if(pHealth <= 0)
						{
							cout<<" A wild Houghton appears!"<<endl;
							return 0;
						}
					}
				}
 
 
 
				if(victory==1 && treasureList.capacity()< 5)
				{
					cout<<" You take the treasure and continue on."<<endl;
					Treasure.pickUpItem(title);
					strcpy(name,title); 
					treasureList.push_back(name);
					cout<<"Would you like to view your inventory? (y/n)"<<endl;
					cin>>choice;
					if(choice=='y')
					{
						for(vector<string>::iterator it=treasureList.begin();it!=treasureList.end();it++)
						{
							cout<<"You are carrying: ";
							cout<<*it<<endl;
						}
					}
					if(treasureList.size()>=1)
					{
						cout<<"Drop an item? (y/n)"<<endl;
						cin>>choice;
						if(choice=='y')
						{
							treasureList.pop_back();
						}
						else
						{
							cout<<" You decide not to drop an item "<<endl;
						}
					}
				}
				if(decision=='r')
				{
					cout<< "Are you really too afraid to pick up the treasure?"<<endl;
					cout<< " You leave the treasure where it lay"<<endl;
					lose=1;
 
				}
				if(decision=='x')
				{
					return 0;
				}
 
				if(victory==-1 &&lose ==-1)
				{
					cout<< "Please re enter a command"<<endl<<">";
					cin>>decision;
 
 
				}
 
 
			}
		}
		victory=-1;
		lose=-1;
		Player.setHealth(pHealth+mDamage*3);
 
 
 
 
 
 
		if(treasureList.size()>=5)
 
		{
			cout<<" You have too many items"<<endl<<"Would you like to drop an item?"<<endl<<">";
			cin>>dropItem;
			if(dropItem=='y')
			{
				treasureList.pop_back();
			}
			else
			{
				cout<<" You decide not to drop an item "<<endl;
			}
		}
 
 
 
		Thief.setLocation(thiefLocation(numRooms));
		thiefIndex=Thief.getLocation();
 
		if(thiefIndex==roomIndex &&treasureList.capacity()!=0)
		{
			treasureList.pop_back();
			cout<<" A thief has stolen some of your treasure!"<<endl;
			cout<<" Would you like to view your inventory? (y/n)  "<<endl<<"> ";
			cin>> choice;
			if (choice=='y')
			{
				cout<<endl;
 
				cout<<" Your inventory contains: "<<endl;
				for (vector<string>::iterator i = treasureList.begin(); i != treasureList.end(); ++i)
				{
					cout << *i << endl;
				}  
 
				cout << endl;
			}
			else if(choice=='n')
			{
				cout<< " You scream obscenities."<<endl<<" No one hears you"<<endl;
 
			}
			else if (choice=='x')
				return 0;
			else
			{
				cout<<" Please re-enter command"<<endl<<"> ";
				cin>>choice;
			}
		}
 
 
 
		int gameOver;
		gameOver=gameEnd(roomIndex);
		if(gameOver==1)
		{
			return 0;
		}
 
		futureRoom(Room, Treasure, roomIndex, numRooms, Monster,Sign);
	}
 
 
 
	in1.close(); //closes the input file
}

Open in new window

SOLUTION
Avatar of jgordos
jgordos
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
figured the problem out