2 //! @brief Driver file to create and execute the test suite and to launch the Map and Campaign Editor
4 //! Brief instruction on how to set CppUnit:
5 //! from: http ://www.comp.nus.edu.sg/~cs3215/tools/cppunitAll.html
7 //! First, to install cppUnit :
9 //! 1. Unpack the CppUnit archive (https://sourceforge.net/projects/cppunit/files/cppunit/1.12.1/) to a directory of your choice, in this example I assume it is D:\.
10 //! 2. Go to D:/cppunit-1.12.1/src and open the CppUnitLibraries.dsw in Visual Studio.
11 //! 3. Select the cppunit project in the Solution Explorer and go to 'Project > Properties > Configuration Properties > Librarian > General. Put "Debug\cppunit.lib" in the ‘Output File’ textbox.
12 //! 4. Right-click on the cppunit project in the Solution Explorer pane and choose Build.
13 //! 5. After successful compilation, D:/cppunit-1.12.1/lib/cppunit.lib is produced which you then need to setup the Visual Studio Linker with (see below).
16 //! To setup a project from scratch for Compilation / Linking:
18 //! 1. Activate 'Project > Properties > C/C++ > Code Generation > Runtime Library > Multi - threaded Debug DLL'
19 //! 2. Go to 'Project > Properties > C/C++ > General'. Put "D:\cppunit-1.12.1\include" in the 'Additional Include Directories' text box.
20 //! 3. Go to 'Project > Properties > Linker > Input'. Put "D:\cppunit-1.12.1\lib\cppunit.lib" in the 'Additional Dependences' text box.
21 //! 4. Go to 'Project > Properties > Build Events > Post-Build Event'. Put '"$(TargetPath)"' in the 'Command Line' textbox.Put 'Unit Tests...' in the 'Description' textbox.
23 #include <cppunit/CompilerOutputter.h>
24 #include <cppunit/extensions/TestFactoryRegistry.h>
25 #include <cppunit/ui/text/TestRunner.h>
33 //! Runs the driver to launch the map and campaign editor.
36 //! Shows the main menu for the map and campaign editor.
37 void showMainMenuForMapAndCampaign();
39 //! Allows the user to select which map to edit.
40 //! @param maps Vector of all current existing maps.
41 vector
<Map
*>* selectMapToEdit(vector
<Map
*>* maps
);
43 //! Allows the user to select which campaign to edit
45 //! @param campaigns Vector of all current existing campaigns
46 //! @param maps Vector of all current existing maps.
47 void selectCampaignToEdit(vector
<Campaign
*>* campaigns
, vector
<Map
*>* maps
);
48 //Map* editMap(Map* map, int mapNumber, string mapName);
50 //! Allows the user to edit a map.
52 //! @param maps Vector of all current existing maps
53 //! @param mapNumber The map's position in the vector.
54 //! @param mapName The map's name.
55 void editMap(Map
* map
, int mapNumber
, string mapName
);
57 //! Allows the user to select how to edit a campaign.
59 //! @param campaigns Vector of all existing campaigns
60 //! @param maps Vector of all current existing maps
61 void editCampaign(Campaign
* campaign
, vector
<Map
*>* maps
);
63 //! Allows the user to add maps to a campaign.
65 //! @param campaigns Vector of all existing campaigns
66 //! @param maps Vector of all current existing maps
67 void addMapToCampaign(Campaign
* campaign
, vector
<Map
*>* maps
);
69 //! Allows the user to remove maps from a campaign.
71 //! @param campaigns Vector of all existing campaigns
72 //! @param maps Vector of all current existing maps
73 void removeMapFromCampaign(Campaign
* campaign
);
75 //! Allows the user to save a new map
77 //! @param maps Vector of all current existing maps
78 void saveMaps(vector
<Map
*>* maps
);
80 //! Allows the user to save a new campaign.
82 //! @param campaigns Vector of all existing campaigns
83 void saveCampaigns(vector
<Campaign
*>* campaigns
);
85 // Methods that accept in out from thr user
87 //! Accepts user to input the number of columns a new map will have.
88 //! @return The number of columns for a new map.
89 int inputColumnsForNewMap();
91 //! Accepts user to input the number of rows a new map will have.
92 //! @return The number of rows for a new map.
93 int inputRowsForNewMap();
95 //! Accepts user to input the row index to edit for a map
96 //! @param rowsInMap The number of rows in the map.
98 //! @return The row index to edit.
99 int inputRowIndexToEdit(int rowsInMap
);
101 //! Accepts user to input the column index to edit for a map
102 //! @param rcolumnsInMap The number of columns in the map.
104 //! @return The row index to edit.
105 int inputColumnIndexToEdit(int columnsInMap
);
107 //! Accepts user to input a char to insert into a map.
108 //! @param row The row index where the char will be inputed.
109 //! @param columns The column index where the char will be inputed.
111 //! @return The char inputed
112 char inputCharObject(int row
, int column
);
114 //! Allows the user to input the name for a map or a campaign.
115 //! @return The name for a map or campaign.
118 //! main() function. Entry point of the program
119 //! It does the following:
120 //! 1. Create a test suite object from the registry as populated by the code in the Test Classes
121 //! 2. Create a test runner that will execute all the tests in the registry
122 //! 3. (optionally) sets an outputter that will output the results
123 //! 4. Run the test cases.
124 int main(int argc
, char* argv
[])
126 // Get the top level suite from the registry
127 CppUnit::Test
*suite
= CppUnit::TestFactoryRegistry::getRegistry().makeTest();
129 // Adds the test to the list of test to run
130 CppUnit::TextUi::TestRunner runner
;
131 runner
.addTest( suite
);
133 // Change the default outputter to a compiler error format outputter
134 runner
.setOutputter( new CppUnit::CompilerOutputter( &runner
.result(),
137 bool wasSucessful
= runner
.run();
140 // Return error code 1 if the one of test failed.
141 return wasSucessful
? 0 : 1;
147 //! Shows a TUI (Text User Interface) to the user to allow them to select different options.
148 void showMainMenuForMapAndCampaign() {
150 vector
<Map
*>* maps
= new vector
<Map
*>();
151 vector
<Campaign
*>* campaigns
= new vector
<Campaign
*>();
155 // Variable that will hold the option for the text based menu
158 // Variables that will hold input
174 cout
<< "****** Map and Campaign Editor Main Menu ******\n";
175 cout
<< "Please select an option.\n\n";
176 cout
<< "Enter 0 to exit.\n";
177 cout
<< "Enter 1 to create a map.\n";
178 cout
<< "Enter 2 to edit a map.\n";
179 cout
<< "Enter 3 to create a campaign.\n";
180 cout
<< "Enter 4 to edit a campaign.\n";
181 cout
<< "Enter 5 to save the created maps\n";
182 cout
<< "Enter 6 to save the created campaigns\n";
184 stringstream
myStream(input
);
185 if (myStream
>> option
) {
192 rows
= inputRowsForNewMap();
193 columns
= inputColumnsForNewMap();
195 maps
->push_back(new Map(rows
, columns
, name
));
196 cout
<< "Created the following map: " << name
<< "\n";
197 maps
->back()->printMap();
201 maps
= selectMapToEdit(maps
);
206 campaigns
->push_back(new Campaign(name
));
210 selectCampaignToEdit(campaigns
, maps
);
218 saveCampaigns(campaigns
);
222 cout
<< "Invalid option, please try again.\n" << endl
;
227 cout
<< "Invalid option, please try again.\n" << endl
;
232 // Delete all maps in vector
233 for (std::vector
<Map
*>::size_type i
= 0; i
!= maps
->size(); i
++) {
234 delete( maps
->at(i
));
239 // Delete all campaigns
240 for (std::vector
<Campaign
*>::size_type i
= 0; i
!= campaigns
->size(); i
++) {
241 delete(campaigns
->at(i
));
242 campaigns
->at(i
) = 0;
247 vector
<Map
*>* selectMapToEdit(vector
<Map
*>* maps
)
250 for (std::vector
<Map
*>::size_type i
= 0; i
!= maps
->size(); i
++) {
252 cout
<< "Map number " << i
<< " : \n" << endl
;
253 maps
->at(i
)->printMap();
257 // Exit option if there are no maps to edit.
258 if (mapCounter
== -1) {
259 cout
<< "There are no existing maps to edit. Returning to the main menu\n";
267 cout
<< "*** Select map to edit ***\n";
268 cout
<< "Enter the number associated with the map to edit: \n";
270 stringstream
myStream(input
);
271 if (myStream
>> option
) {
272 if (option
<= mapCounter
) {
276 //Map* map = maps->at(option);
278 //map = editMap(map, option);
279 editMap(maps
->at(option
), option
, maps
->at(option
)->getMapName());
281 // No need to delete map since the new keyword was not used.
284 cout
<< "Invalid option, please try again.\n" << endl
;
288 cout
<< "Invalid option, please try again.\n" << endl
;
291 return maps
; ////////////////////////////////////////////////////////////////////// redundant?
294 void selectCampaignToEdit(vector
<Campaign
*>* campaigns
, vector
<Map
*>* maps
)
296 int campaignCounter
= -1;
297 for (std::vector
<Campaign
*>::size_type i
= 0; i
!= campaigns
->size(); i
++) {
299 cout
<< "Campaign number " << i
<< " : " << campaigns
->at(i
)->getCampaignName() << "\n" << endl
;
303 // Exit option if there are no maps to edit.
304 if (campaignCounter
== -1) {
305 cout
<< "There are no existing campaigns to edit. Returning to the previous menu\n";
313 cout
<< "*** Select campaign to edit ***\n";
314 cout
<< "Enter the number associated with the campaign to edit: \n";
316 stringstream
myStream(input
);
317 if (myStream
>> option
) {
318 if (option
<= campaignCounter
) {
321 editCampaign(campaigns
->at(option
), maps
);
323 // No need to delete map since the new keyword was not used.
326 cout
<< "Invalid option, please try again.\n" << endl
;
330 cout
<< "Invalid option, please try again.\n" << endl
;
335 void editMap(Map
* map
, int mapNumber
, string mapName
)
338 bool isInputValid
= false;
340 // String of inputValue
345 bool stopEditingMap
= false;
347 // Outer loop to continue allowing the user to edit the selected map.
349 cout
<< "*** Editing map" << mapNumber
<< "\\" << mapName
<< " ***\n";
351 int rowsInMap
= map
->getRows();
352 int row
= inputRowIndexToEdit(rowsInMap
);
355 int columnsInMap
= map
->getColumns();
356 int column
= inputColumnIndexToEdit(columnsInMap
);
359 char inputObject
= inputCharObject(row
, column
);
361 // Edit the cell if it is not empty
362 if (!map
->isOccupied(row
, column
)) {
363 map
->fillCell(row
, column
, inputObject
);
365 cout
<< "Result: \n";
369 cout
<< "An object already exists at that position.\n";
372 // Ask the user if they want to continue editing the map
374 cout
<< "Enter 0 to cancel and return to the main menu \n";
375 cout
<< "Enter 1 to continue editing the map \n";
379 // Convert from string to number
380 stringstream
myStream(input
);
381 if (myStream
>> option
) {
385 //stopEditingMap = true;
386 //isInputValid = true;
393 cout
<< "Invalid option, please try again.\n" << endl
;
398 cout
<< "Invalid option, please try again.\n" << endl
;
400 } while (!isInputValid
);
402 } while (!stopEditingMap
);
406 void editCampaign(Campaign
* campaign
, vector
<Map
*>* maps
)
408 bool stopEditingCampaign
= false;
409 bool isInputValid
= false;
412 // Outer loop to continue allowing the user to edit the selected campaign.
414 cout
<< "*** Edit campaign ***\n";
417 // Show menu to allow the user to edit the campaign.
419 cout
<< "Enter 0 to cancel and return to the main menu \n";
420 cout
<< "Enter 1 to add a map to the campaign \n";
421 cout
<< "Enter 2 to remove a map from the campaign \n";
425 // Convert from string to number.
426 stringstream
myStream(input
);
427 if (myStream
>> option
) {
433 addMapToCampaign(campaign
, maps
);
438 removeMapFromCampaign(campaign
);
442 cout
<< "Invalid option, please try again.\n" << endl
;
447 cout
<< "Invalid option, please try again.\n" << endl
;
449 } while (!isInputValid
);
451 isInputValid
= false;
452 // Ask the user if they want to continue editing the campaign
454 cout
<< "Enter 0 to cancel and return to the main menu \n";
455 cout
<< "Enter 1 to continue editing the campaign \n";
458 // This code converts from string to number safely.
459 stringstream
myStream(input
);
460 if (myStream
>> option
) {
463 stopEditingCampaign
= true;
471 cout
<< "Invalid option, please try again.\n" << endl
;
476 cout
<< "Invalid option, please try again.\n" << endl
;
478 } while (!isInputValid
);
480 } while (!stopEditingCampaign
);
483 void addMapToCampaign(Campaign
* campaign
, vector
<Map
*>* maps
)
487 if (maps
->size() == 0) {
488 cout
<< "There are no available maps\n";
495 bool stopAddingMaps
= false;
497 // Outer loop to continue allowing the user to add maps to the campaign
499 cout
<< "*** Add maps to campaign ***\n";
500 campaign
->printMaps();
503 cout
<< "Available maps\n";
505 for (std::vector
<Map
*>::size_type i
= 0; i
!= maps
->size(); i
++) {
506 cout
<< "Map " << i
<< " : ";
507 maps
->at(i
)->printMap();
513 cout
<< "Enter the number associated with the map to add it to the campaign: \n";
515 stringstream
myStream(input
);
516 if (myStream
>> option
) {
517 if (option
<= mapCounter
) {
520 campaign
->addMap(maps
->at(option
));
524 cout
<< "Invalid option, please try again.\n" << endl
;
528 cout
<< "Invalid option, please try again.\n" << endl
;
533 // Ask the user if they want to continue editing the campaign
535 cout
<< "Enter 0 to cancel and return to the previous menu \n";
536 cout
<< "Enter 1 to continue adding maps to the campaign \n";
540 // This code converts from string to number safely.
541 stringstream
myStream(input
);
542 if (myStream
>> option
) {
551 cout
<< "Invalid option, please try again.\n" << endl
;
556 cout
<< "Invalid option, please try again.\n" << endl
;
560 } while (!stopAddingMaps
);
563 void removeMapFromCampaign(Campaign
* campaign
)
569 vector
<Map
*>* maps
= campaign
->getMaps();
571 // Outer loop to continue allowing the user to add maps to the campaign
573 cout
<< "*** Remove maps from campaign ***\n";
574 if (campaign
->getMapsInCampaign() == 0) {
575 cout
<< "The campaign does not contain any maps. Going back to the previous menu\n";
582 cout
<< "Current maps in campaign " << campaign
->getCampaignName() << "\n";
584 for (std::vector
<Map
*>::size_type i
= 0; i
!= maps
->size(); i
++) {
585 cout
<< "Map " << i
<< " : ";
586 maps
->at(i
)->printMap();
590 cout
<< "Enter the number associated with the map to remove it to the campaign: \n";
592 stringstream
myStream(input
);
593 if (myStream
>> option
) {
594 if (option
<= mapCounter
) {
597 campaign
->removeMap(maps
->at(option
));
601 cout
<< "Invalid option, please try again.\n" << endl
;
605 cout
<< "Invalid option, please try again.\n" << endl
;
610 // Ask the user if they want to continue editing the campaign
612 cout
<< "Enter 0 to cancel and return to the previous menu \n";
613 cout
<< "Enter 1 to continue removing maps from the campaign \n";
617 // This code converts from string to number safely.
618 stringstream
myStream(input
);
619 if (myStream
>> option
) {
628 cout
<< "Invalid option, please try again.\n" << endl
;
633 cout
<< "Invalid option, please try again.\n" << endl
;
640 void saveMaps(vector
<Map
*>* maps
)
642 cout
<< "*** Save maps ***\n";
644 cout
<< "There are no maps to save\n";
648 string
const folderName
= "./maps/";
650 for (std::vector
<Map
*>::size_type i
= 0; i
!= maps
->size(); i
++) {
651 // Make sure the map is valid before saving
652 if (maps
->at(i
)->validatePath()) {
653 string pathName
= folderName
+ maps
->at(i
)->getMapName() + ".txt";
654 //string pathName = "./maps/maptest.txt"; //works if folder exists
655 ofstream
mapFile(pathName
);
656 for (int row
= 0; row
< maps
->at(i
)->getRows(); row
++)
658 for (int column
= 0; column
< maps
->at(i
)->getColumns(); column
++)
660 if (mapFile
.is_open())
662 mapFile
<< maps
->at(i
)->getCharObject(row
, column
) << ",";
664 else cout
<< "Unable to open file\n";
671 cout
<< "Unable to save map " << maps
->at(i
)->getMapName() << " because it is invalid.\n";
675 cout
<< "Completed saving maps into the maps folder\n";
678 void saveCampaigns(vector
<Campaign
*>* campaigns
)
680 // Campaigns are only saved if all the maps within them are valid
681 cout
<< "*** Save campaigns ***\n";
682 if (campaigns
->empty()) {
683 cout
<< "There are no campaigns to save\n";
687 string
const folderName
= "./campaigns/";
688 bool isCampaignValid
= true;
689 string campaignName
= "";
690 // Make sure all the maps belonging to a campaign are valid before saving the campaign.
691 for (std::vector
<Campaign
*>::size_type c
= 0; c
!= campaigns
->size(); c
++) {
693 isCampaignValid
= true;
694 campaignName
= campaigns
->at(c
)->getCampaignName();
695 // Get vector of maps for campaign
696 vector
<Map
*>* maps
= campaigns
->at(c
)->getMaps();
698 for (std::vector
<Map
*>::size_type i
= 0; i
!= maps
->size(); i
++) {
700 // Make sure the map is valid before saving
701 if (!(maps
->at(i
)->validatePath())) {
702 isCampaignValid
= false;
706 if (isCampaignValid
) {
707 string pathName
= folderName
+ campaigns
->at(c
)->getCampaignName() + ".txt";
708 ofstream
mapFile(pathName
);
710 for (std::vector
<Map
*>::size_type i
= 0; i
!= maps
->size(); i
++) {
711 for (int row
= 0; row
< maps
->at(i
)->getRows(); row
++)
713 for (int column
= 0; column
< maps
->at(i
)->getColumns(); column
++)
715 if (mapFile
.is_open())
717 mapFile
<< maps
->at(i
)->getCharObject(row
,column
) << ",";
719 else cout
<< "Unable to open file\n";
723 mapFile
<< "\n*****\n";
726 cout
<< "Saved campaign " << campaignName
<< endl
;
729 cout
<< "Unable to save campaign " << campaignName
<< " because it contains maps which are invalid.\n";
735 //! Accepts user input for the number of columns to use in the new map.
736 int inputColumnsForNewMap() {
738 bool isInputValid
= false;
742 cout
<< "Please enter the number of columns in the map (minimum 1):\n";
745 // This code converts from string to number safely.
746 stringstream
myStream(input
);
747 if (myStream
>> columns
&& columns
> 0) {
751 cout
<< "Invalid number, please try again.\n" << endl
;
753 } while (!isInputValid
);
757 //! Accepts user input for the number of rows to use in the new map.
758 int inputRowsForNewMap() {
760 bool isInputValid
= false;
763 // Input for for rows
765 cout
<< "Please enter the number of rows in the map (minimum 1):\n";
768 stringstream
myStream(input
);
769 if (myStream
>> rows
&& rows
> 0) {
773 cout
<< "Invalid number, please try again.\n" << endl
;
775 } while (!isInputValid
);
779 //! Accepts the row the index the user wishes to edit in an existing map.
780 int inputRowIndexToEdit(int rowsInMap
)
783 bool isInputValid
= false;
785 // String of inputValue
790 cout
<< "Please enter the row you wish to edit: \n";
793 stringstream
myStream(input
);
794 if (myStream
>> row
&& row
>= 0 && row
< rowsInMap
) {
798 cout
<< "Invalid number, please try again.\n" << endl
;
800 } while (!isInputValid
);
804 int inputColumnIndexToEdit(int columnsInMap
)
807 bool isInputValid
= false;
809 // String of inputValue
812 // Input for the column
814 cout
<< "Please enter the column you wish to edit: \n";
817 // This code converts from string to number safely.
818 stringstream
myStream(input
);
819 if (myStream
>> column
&& column
>= 0 && column
< columnsInMap
) {
823 cout
<< "Invalid number, please try again.\n" << endl
;
825 } while (!isInputValid
);
829 //! Accepts the char object the user wishes to enter into a cell.
830 char inputCharObject(int row
, int column
)
832 bool isInputValid
= false;
837 cout
<< "What would you like to enter at position " << row
<< ", " << column
<< ": \n";
838 cout
<< "Enter a blank space to insert an empty cell \n";
839 cout
<< "Enter 's' to insert a starting cell \n";
840 cout
<< "Enter 'e' to insert an ending cell \n";
841 cout
<< "Enter 't' to insert a chest \n";
842 cout
<< "Enter 'm' to insert a monster \n";
843 cout
<< "Enter '|' (pipe/ shift + backslash) to insert a wall \n";
846 if (input
.length() == 1) {
847 inputObject
= input
[0];
848 // Use constants later on.
849 if (inputObject
== ' ' || inputObject
== 's' || inputObject
== 'e' || inputObject
== 't' || inputObject
== 'm' || inputObject
== '|') {
853 cout
<< "Invalid input, please try again.\n" << endl
;
857 cout
<< "Invalid input, please try again.\n" << endl
;
859 } while (!isInputValid
);
863 //! Accepts input to use as the name for a map or campaign
866 bool isInputValid
= false;
872 cout
<< "Enter the name for the map or campaign:\n";
877 cout
<< "You entered: " << input
<< "\n";
878 cout
<< "Enter 0 to cancel\n";
879 cout
<< "Enter 1 to confirm\n";
882 stringstream
myStream(input
);
883 if (myStream
>> option
) {
886 isInputValid
= false;
894 cout
<< "Invalid option, please try again.\n" << endl
;
899 cout
<< "Invalid option, please try again.\n" << endl
;
903 cout
<< "Cannot enter an empty string. Please try again.\n";
905 } while (!isInputValid
);
909 //! Driver that calls showMainMenuForMapAndCampaign to run the Map and Campaign editor
912 showMainMenuForMapAndCampaign();