#include “basicdungeon.h”
using namespace core::dungeon;
/* ——————————————————————————
* BasicDungeon member implementations
* —————————————————————————–*/
BasicDungeon::BasicDungeon()
{
}
/* ——————————————————————————
* RockChamber member implementations
* —————————————————————————–*/
RockChamber::RockChamber()
{
}
/* ——————————————————————————
* QuartzChamber member implementations
* —————————————————————————–*/
QuartzChamber::QuartzChamber()
{
}
/* ——————————————————————————
* BasicWall member implementations
* —————————————————————————–*/
RockWall::RockWall()
{
}
#include “character.h”
using core::Character;
Character::Character(const std::string &name)
: _name{name}
{
}
const std::string& Character::name() const {
return _name;
}
std::ostream& operator<<(std::ostream &stream, const Character &character) {
stream << character.name();
return stream;
}
#include "commondungeon.h"
using namespace core::dungeon;
OpenDoorway::OpenDoorway()
{
}
#include "creatures.h"
using namespace core::creatures;
/* ------------------------------------------------------------------------------
* Creature member implementations
* -----------------------------------------------------------------------------*/
Creature::Creature(const std::string &name)
: _name{name}
{
}
const std::string& Creature::name() const {
return _name;
}
#include "csvfile.h"
using namespace data;
CsvFile::CsvFile(std::istream &input)
{
// TODO: implement the constructor
}
int CsvFile::numberOfColumns() const
{
// TODO: implement this method. See header for description.
return -10;
}
int CsvFile::numberOfRows() const
{
// TODO: implement this method. See header for description.
return -10;
}
std::string CsvFile::at(int row, int column) const
{
// TODO: implement this method. See header for description.
return "not yet implemented";
}
std::string CsvFile::headerAt(int column) const
{
// TODO: implement this method. See header for description.
return "not yet implemented";
}
int CsvFile::columnIndexOf(const std::string &columnName) const
{
// TODO: implement this method. See header for description.
return -10;
}
#include "door.h"
using namespace core::dungeon;
Door::Door()
{
}
#include "dungeon.h"
using namespace core::dungeon;
Dungeon::Dungeon()
: _rooms{}
{
}
// DO NOT modify implementation below this comment
std::shared_ptr
auto roomIterator = _rooms.find(id);
if (roomIterator != _rooms.end()) {
return roomIterator->second;
}
return std::shared_ptr
}
bool Dungeon::addRoom(std::shared_ptr
if (!_rooms.count(newRoom->id())) {
_rooms[newRoom->id()] = newRoom;
return true;
}
return false;
}
#include “game.h”
#include “testingsettings.h”
#include
using namespace core;
// TODO: Add additional implementation here
// Do not change/remove the initialisation of _randomGenerator and _realDistribution, otherwise change as needed.
Game::Game()
: _randomGenerator{uint32_t(time(nullptr))}, _realDistribution{0.0, 1.0}
{
}
// DO NOT modify implementation below this comment
int Game::randomIntBetweenInc(int min, int max) {
#if INPUT_SCRIPT
return min; // for consistency when using the input script
#else
if (min == max) return max;
if (max < min) std::swap(min, max);
int diff{max + 1 - min};
return int(_randomGenerator() % unsigned(diff)) + min;
#endif
}
int Game::randomIntBetweenEx(int min, int max) {
#if INPUT_SCRIPT
return max - 1; // for consistency when using the input script
#else
if (min == max) return max; // technically invalid for an exclusive range
if (max < min) std::swap(min, max);
int diff{max - min};
return int(_randomGenerator() % unsigned(diff)) + min;
#endif
}
double Game::randomDouble() {
#if INPUT_SCRIPT
return 1.0; // for consistency when using the input script.
#else
return _realDistribution(_randomGenerator);
#endif
}
#include "magicaldungeon.h"
using namespace core::dungeon;
/* ------------------------------------------------------------------------------
* MagicalDungeon member implementations
* -----------------------------------------------------------------------------*/
MagicalDungeon::MagicalDungeon()
{
}
/* ------------------------------------------------------------------------------
* EnchantedLibrary member implementations
* -----------------------------------------------------------------------------*/
EnchantedLibrary::EnchantedLibrary()
{
}
/* ------------------------------------------------------------------------------
* AlchemistsLaboratory member implementations
* -----------------------------------------------------------------------------*/
AlchemistsLaboratory::AlchemistsLaboratory()
{
}
/* ------------------------------------------------------------------------------
* MagicWall member implementations
* -----------------------------------------------------------------------------*/
MagicWall::MagicWall()
{
}
#include "menuinterface.h"
#include
#include
#include “testingsettings.h”
#define AUTHOR “
#define TITLE “
#if INPUT_SCRIPT
#define SCRIPT_PATH “../assignment1-dungeon_crawler/input_script.txt”
#define OUT_FILE_PATH “../assignment1-dungeon_crawler/output_gen.txt”
#endif
/* ——————————————————————————
* NOTE: DO NOT edit this file other than providing your name and game title to the
* `AUTHOR` and `TITLE` macros, respectively.
* Enable testing mode and set options in the testingsettings.h file.
* It may be necessary to change the path to the input script, depending on your
* configuration: see SCRIPT_PATH macro definition above.
* —————————————————————————–*/
/**
* @mainpage
*
* There are three forms of the main function in this file so that it can run in
* three modes: normal, input script, and testing. This is done using conditional
* compilation and is configured through `testingsettings.h`.
*
* In normal mode, the MenuInterface will be run and attached to standard in and
* standard out.
*
* In input script mode, the Menu Interface will be run and attached to a file
* for input and (optionally) a file for output. This will be used as a quick test
* of the general functionality of your implementation. You can use it yourself
* to test as you go to ensure that your implementation conforms to the expected
* commands.
*
* In testing mode, a simple unit testing suite will be executed. A small example
* has been provided, but you are encouraged to implement tests as you go to
* ensure the parts of your implementation are working. This saves time as it makes
* it easier to track down errors for “submodules” this way, rather than having to
* test everything through the menu-driven interface constantly.
*/
using core::MenuInterface;
#if not TESTING
#if not INPUT_SCRIPT
/**
* @brief main Simple main function that runs the MenuInterface until quit.
* @return exit code, 0 is success
*/
int main()
{
MenuInterface m{std::cout, std::cin};
m.displayWelcome(AUTHOR, TITLE);
m.run();
return 0;
}
#else
#include
#include
/**
* @brief main Simple main function runs game using the input script.
* @return
*/
int main()
{
// Using QDir to provide sensible error useful error message
// if the script file cannot be found.
QDir path{SCRIPT_PATH};
std::fstream in{path.absolutePath().toStdString()};
if (in.fail()) {
std::cout << "Unable to find file: " << path.absolutePath().toStdString() << std::endl
<< "Current path: " << QDir::currentPath().toStdString() << std::endl;
return 1;
}
#if OUTPUT_SCRIPT
QDir outPath{OUT_FILE_PATH};
std::ofstream out{outPath.absolutePath().toStdString()};
if (out.fail()) {
std::cout << "Unable to open out file: " << outPath.absolutePath().toStdString() << std::endl
<< "Current path: " << QDir::currentPath().toStdString() << std::endl;
return 1;
}
#else
std::ostream& out = std::cout;
#endif
MenuInterface m{out, in};
m.displayWelcome(AUTHOR, TITLE);
m.run();
return 0;
}
#endif
#else
#include "testing.h"
/**
* @brief main run testing code.
* @return
*/
int main() {
Testing test{};
std::cout << "Running tests ..." << std::endl;
test.runTests(); // Modify which tests are run in the implementation of runTests()
test.printTestResults(std::cout);
return 0;
}
#endif
#include "menuinterface.h"
#include
using namespace core;
MenuInterface::MenuInterface(std::ostream &display, std::istream &input)
: _display{display}, _input{input}, _currentMenu{Menu::Main} {
}
void MenuInterface::displayWelcome(const std::string &author, const std::string &title) const {
std::string welcomeText{“Welcome to ” + title};
std::string authorText{“Developed by ” + author};
std::string comp3023{“COMP 3023 Software Development with C++”};
unsigned int columns{static_cast
_display << centre(columns, welcomeText.size()) << welcomeText << std::endl
<< centre(columns, authorText.size()) << authorText << std::endl
<< centre(columns, comp3023.size()) << comp3023 << std::endl;
}
void MenuInterface::run() {
displayMenu();
while (processSelection(getCharacterInput()) && _input) {
displayMenu();
}
}
void MenuInterface::displayMenu() const {
waitUntillNewline();
switch (_currentMenu) {
case Menu::Main:
displayMainMenu();
break;
case Menu::CharacterDetails:
characterDetailsMenu();
break;
case Menu::DungeonSelect:
dungeonTypeMenu();
break;
case Menu::Action:
actionMenu();
break;
case Menu::Combat:
combatMenu();
break;
}
}
bool MenuInterface::processSelection(char selection) {
if (!_input) return false; // graceful exit when input ends
switch (_currentMenu) {
case Menu::Main:
return processMainMenu(tolower(selection));
case Menu::CharacterDetails:
processCharacterDetails(tolower(selection));
break;
case Menu::DungeonSelect:
processDungeonType(tolower(selection));
break;
case Menu::Action:
processAction(tolower(selection));
break;
case Menu::Combat:
processCombatAction(tolower(selection));
}
return true;
}
char MenuInterface::getCharacterInput() const {
char input;
_input >> input;
_input.ignore(std::numeric_limits
echo(input); // for when running the input script
return input;
}
int MenuInterface::getIntInput() const {
int input;
_input >> input;
_input.ignore(std::numeric_limits
while (!_input) {
_input.clear();
warnSelectionInvalid(char(_input.peek()));
_input.ignore(std::numeric_limits
_input >> input;
_input.ignore(std::numeric_limits
}
echo(input); // for when running the input script
return input;
}
void MenuInterface::warnSelectionInvalid(char selection) const {
_display << "Sorry, \'" << selection << "\' is not a valid option, please try again."
<< std::endl;
}
void MenuInterface::setMenu(Menu newMenu) {
_currentMenu = newMenu;
}
void MenuInterface::displayMainMenu() const {
_display << "What would you like to do?" << std::endl;
_display << " (p)lay the game" << std::endl;
_display << " (c)haracter details" << std::endl;
_display << " (q)uit" << std::endl;
}
bool MenuInterface::processMainMenu(char selection) {
switch (selection) {
case 'p':
playGame();
break;
case 'c':
switchToCharacterMenu();
break;
case 'q':
return quitGame();
default:
warnSelectionInvalid(selection);
}
return true;
}
void MenuInterface::playGame() {
// TODO: implement this member function.
}
void MenuInterface::createCharacter() {
// TODO: implement this member function.
}
void MenuInterface::dungeonTypeMenu() const {
// TODO: implement this member function.
_display << "TODO: any key will return to main menu" << std::endl;
}
void MenuInterface::processDungeonType(char selection) {
// TODO: implement this member function.
setMenu(Menu::Main);
}
void MenuInterface::switchToCharacterMenu() {
// TODO: implement this member function
setMenu(Menu::CharacterDetails);
}
bool MenuInterface::quitGame() const {
// TODO: complete implementation
return !confirm("Are you sure you want to quit?");
}
void MenuInterface::characterDetailsMenu() const {
// TODO: implement this member function.
_display << "TODO: any key will return to main menu" << std::endl;
}
void MenuInterface::processCharacterDetails(char selection) {
// TODO: implement this member function.
setMenu(Menu::Main);
}
void MenuInterface::displayWeaponDetails() {
// TODO: implement this member function
}
void MenuInterface::actionMenu() const {
// TODO: implement this member function.
_display << "TODO: any key will return to main menu" << std::endl;
}
void MenuInterface::processAction(char selection) {
// TODO: implement this member function.
setMenu(Menu::Main);
}
void MenuInterface::combatMenu() const {
// TODO: implement this member function.
_display << "TODO: any key will return to main menu" << std::endl;
}
void MenuInterface::processCombatAction(char selection) {
// TODO: implement this member function.
setMenu(Menu::Main);
}
void MenuInterface::doNavigate() {
// TODO: implement this member function
}
void MenuInterface::pickupWeapon() {
// TODO: implement this member function
}
void MenuInterface::compareWeapons() {
// TODO: implement this member function
}
void MenuInterface::doAttack() {
// TODO: implement this member function
}
void MenuInterface::useSpecialAbility() {
// TODO: implement this member function
}
void MenuInterface::leaveDungeon() {
// TODO: implement this member function
}
bool MenuInterface::confirm(const std::string &confirmationPrompt) const {
// TODO: implement this member function.
// Do not forget to validate the user's confirmation selection
return true;
}
#include "room.h"
using namespace core::dungeon;
Room::Room(int id)
: _id{id}
{
}
int Room::id() {
return _id;
}
#include "testing.h"
#include "basicdungeon.h"
#include "character.h"
#include "commondungeon.h"
#include "creatures.h"
#include "csvfile.h"
#include "door.h"
#include "dungeon.h"
#include "game.h"
#include "weapons.h"
#include "magicaldungeon.h"
#include "room.h"
#include "wall.h"
#include
#include
#include
#include
#include
/*
* IMPLEMENT your tests in this file as required.
*
* You may need to edit the original test implementations as you implement your design.
* The original test implementations are just simple examples that do not necessarily
* reflect the final application.
*/
using namespace core;
using namespace data;
using namespace dungeon;
using namespace creatures;
using std::cout;
using std::endl;
using std::setw;
void Testing::runTests() {
cout << std::left << std::setfill('.');
csvFileTestSuite(); // Runs all of the CsvFile tests
cout << setw(72) << "Character class tests " << testCharacter() << endl;
cout << setw(72) << "Creature class tests " << testCreature() << endl;
cout << setw(72) << "Door class tests " << testDoor() << endl;
cout << setw(72) << "Dungeon class tests " << testDungeon() << endl;
cout << setw(72) << "Game class tests " << testGame() << endl;
cout << setw(72) << "Weapon class tests " << testWeapon() << endl;
cout << setw(72) << "Room class tests " << testRoom() << endl;
cout << setw(72) << "Wall class tests " << testWall() << endl;
}
// This is an example of a simple way of performing your tests.
// It is incomplete, so you will need to extend it if you intend to continue with it.
std::string Testing::testCharacter() {
_failure = false; // ensure this is at the beggining of each test
std::string name{"Character Name"};
Character c{name};
equal
// TODO: complete the testing of the Character class
return passFailText();
}
std::string Testing::testCreature() {
_failure = false; // ensure this is at the beggining of each test
std::string name{“Creature Name”};
Creature c{name};
equal
// TODO: complete the testing of the Creature class(es): can be removed
return passFailText();
}
std::string Testing::testDoor() {
_failure = false; // ensure this is at the beggining of each test
// TODO: complete the testing of the Door class(es): can be removed
// return passFailText();
return “Skipped”;
}
std::string Testing::testDungeon() {
_failure = false; // ensure this is at the beggining of each test
int roomId{1};
std::shared_ptr
Dungeon dungeon{};
dungeon.addRoom(room);
equal(room, dungeon.retrieveRoom(roomId), “Dungeon .add/.retrieveRoom() failure, does not return room that was added”);
// TODO: complete the testing of the Dungeon class(es): can be removed
// return passFailText();
return “Skipped”;
}
std::string Testing::testGame() {
_failure = false;
Game game{};
// TODO: implement the testing of the Game class
// The following tests the random number generation.
int value{game.randomIntBetweenInc(5, 0)};
greaterThan(-1, value, “Swapping the min and max (incl.) did not work. Got negative value.”);
lessThan(6, value, “Swapping the min and max (incl.) did not work. value out of range.”);
value = game.randomIntBetweenEx(5, 0);
greaterThan(-1, value, “Swapping the min and max (excl.) did not work. Got negative value.”);
lessThan(5, value, “Swapping the min and max (excl.) did not work. value out of range.”);
for (int i{0}; i < 1000; ++i) {
// Not really a good test for this, but just in case.
int value = game.randomIntBetweenInc(2, 5);
greaterThan(1, value, "Game .randomIntBetweenInc somehow generated a value out of range");
lessThan(6, value, "Game .randomIntBetweenInc somehow generated a value out of range");
}
for (int i{0}; i < 1000; ++i) {
// Not really a good test for this, but just in case.
int value = game.randomIntBetweenEx(2, 5);
greaterThan(1, value, "Game .randomIntBetweenEx somehow generated a value out of range");
lessThan(5, value, "Game .randomIntBetweenEx somehow generated a value out of range");
}
for (int i{0}; i < 1000; ++i) {
// Not really a good test for this, but just in case.
double value = game.randomDouble();
double tinyValueBelow1{std::nextafter(0.0, std::numeric_limits
greaterThan(tinyValueBelow1, value, “Game .randomDouble somehow generated a value out of range”);
lessThan(1.0, value, “Game .randomDouble somehow generated a value out of range”);
}
return passFailText();
}
std::string Testing::testWeapon() {
_failure = false; // ensure this is at the beggining of each test
// TODO: complete the testing of the Item class(es): can be removed
// return passFailText();
return “Skipped”;
}
std::string Testing::testRoom() {
_failure = false;
int roomId{1};
Room room{roomId};
equal(roomId, room.id(), “Room .id() does not match constructor value”);
// TODO: complete the testing of the Character class
return passFailText();
}
std::string Testing::testWall() {
_failure = false; // ensure this is at the beggining of each test
// TODO: complete the testing of the Wall class(es): can be removed
// return passFailText();
return “Skipped”;
}
// TODO: implement the rest of your tests here
// CsvFile tests: Do NOT modify! (except in the following suggestion)
// It is recommended that you perform the following:
// – Comment out all but the first test.
// – Once the first test passes, activate the second while leaving the first
// test active.
// – Once the second test passes, move to the third test, etc.
// Doing it this way will incrementally build up the functionality of your
// CsvFile class while ensuring all of the previous tests still pass as you
// make changes to your implementation.
void Testing::csvFileTestSuite()
{
cout << setw(72) << "CsvFile: Test Empty CSV file " << testLoadFailureForEmptyCsvFile() << endl;
cout << setw(72) << "CsvFile: Test CSV file with Header but no rows " << testLoadSuccessForHeaderButNoDataCsvFile() << endl;
cout << setw(72) << "CsvFile: Test Out of Range Returns Empty string " << testOutOfRangeReturnsEmptyString() << endl;
cout << setw(72) << "CsvFile: Test Correct Header Fields read in " << testHeaderFieldsCorrectlyRead() << endl;
cout << setw(72) << "CsvFile: Test Correct Row data read in and accessible " << testCommaSeparatedRowDataAccessible() << endl;
cout << setw(72) << "CsvFile: Test Multi-Row CSV data is accessible " << testMultipleRowsOfData() << endl;
cout << setw(72) << "CsvFile: Test Load failure for differing number of columns " << testLoadFailureOnRowWithDifferingNumberOfColumns() << endl;
cout << setw(72) << "CsvFile: Test preservation of whitespace in fields " << testPreservationOfWhitespaceInFields() << endl;
cout << setw(72) << "CsvFile: Test line endings of last line " << testLineEndingOnLastLine() << endl;
cout << setw(72) << "CsvFile: Test double quoted fields (no internal quotes) " << testDoubleQuotedFields() << endl;
cout << setw(72) << "CsvFile: Test double quoted fields (mixed some quoted,some not) " << testDoubleQuotedFieldsMixedWithUnquoted() << endl;
cout << setw(72) << "CsvFile: Test replace of '\\n' with newline character in quoted fields " << testReplacementOfBlackslashNInQuotedFieldsWithNewline() << endl;
cout << setw(72) << "CsvFile: Test double quotes within fields " << testDoubleQuotesWithinFields() << endl;
cout << setw(72) << "CsvFile: Test putting it all together, load sample creature file " << testReadingCsvDataFromFile() << endl;
}
std::string Testing::testLoadFailureForEmptyCsvFile()
{
std::stringstream data{""};
CsvFile csvFile{data};
equal(-1, csvFile.numberOfRows(), "numberOfRows() must indicate load failure for empty input data");
equal(-1, csvFile.numberOfColumns(), "numberOfColumns() must indicate load failure for empty input data");
equal
equal
equal(-1, csvFile.columnIndexOf(“Name”), “columnIndexOf(string) must return -1 for empty input data”);
return passFailText();
}
std::string Testing::testLoadSuccessForHeaderButNoDataCsvFile()
{
std::stringstream data{“Header”};
CsvFile csvFile{data};
equal(0, csvFile.numberOfRows(), “numberOfRows() must indicate the number of rows in the data for successful load”);
equal(1, csvFile.numberOfColumns(), “numberOfColumns() must indicate the number of columns for successful load”);
equal
equal
equal(1, csvFile.columnIndexOf(“Header”), “columnIndexOf(string) must return index for for successful load”);
return passFailText();
}
std::string Testing::testOutOfRangeReturnsEmptyString()
{
std::stringstream data{R”:(Header1,Header2
Cell 1,Cell 2
):”};
CsvFile csvFile{data};
equal
equal
equal
equal
equal
equal
return passFailText();
}
std::string Testing::testHeaderFieldsCorrectlyRead()
{
std::stringstream data{R”:(Header1,Header2,Header3):”};
CsvFile csvFile{data};
equal(0, csvFile.numberOfRows(), “numberOfRows() must indicate zero, as only the header is present”);
equal(3, csvFile.numberOfColumns(), “numberOfColumns() must indicate 3 columns for the three header fields”);
equal
equal
equal
return passFailText();
}
std::string Testing::testCommaSeparatedRowDataAccessible()
{
std::stringstream data{R”:(Header1,Header2,Header3
Field1,Field2,Field3):”};
CsvFile csvFile{data};
equal(1, csvFile.numberOfRows(), “numberOfRows() must indicate 1, as the header + 1 row is present”);
equal(3, csvFile.numberOfColumns(), “numberOfColumns() must indicate 3 columns for the three fields”);
equal
equal
equal
return passFailText();
}
std::string Testing::testMultipleRowsOfData()
{
std::stringstream data{R”:(Header1,Header2,Header3
Row1Field1,Row1Field2,Row1Field3
Row2Field1,Row2Field2,Row2Field3
Row3Field1,Row3Field2,Row3Field3):”};
CsvFile csvFile{data};
equal(3, csvFile.numberOfRows(), “numberOfRows() must indicate 3, as the header + 3 rows are present”);
equal(3, csvFile.numberOfColumns(), “numberOfColumns() must indicate 3 columns for the three fields”);
equal
equal
equal
equal
equal
equal
equal
equal
equal
return passFailText();
}
std::string Testing::testLoadFailureOnRowWithDifferingNumberOfColumns()
{
std::stringstream dataExtraColumnInRow{R”:(Header1,Header2
Field1,Field2,Field3Error):”};
CsvFile csvFile{dataExtraColumnInRow};
equal(-1, csvFile.numberOfRows(), “numberOfRows() must indicate load failure for row with extra column”);
equal(-1, csvFile.numberOfColumns(), “numberOfColumns() must indicate load failure for row with extra column”);
std::stringstream dataMissingColumnInRow{R”:(Header1,Header2
Field1):”};
csvFile = CsvFile{dataMissingColumnInRow};
equal(-1, csvFile.numberOfRows(), “numberOfRows() must indicate load failure for row with missing column”);
equal(-1, csvFile.numberOfColumns(), “numberOfColumns() must indicate load failure for row with missing column”);
return passFailText();
}
std::string Testing::testPreservationOfWhitespaceInFields()
{
std::stringstream data{” Header1, Header2,Header3 ,Header 4, Header 5 ,Header6 \n”
” Field1, Field2,Field3 ,Field 4, Field 5 ,Field6 “};
CsvFile csvFile{data};
equal(1, csvFile.numberOfRows(), “numberOfRows() must be 1 for whitespace test”);
equal(6, csvFile.numberOfColumns(), “numberOfColumns() must be 6 for whitespace test”);
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
return passFailText();
}
std::string Testing::testLineEndingOnLastLine()
{
std::stringstream data{R”:(Header1
Field1):”};
CsvFile csvFile{data};
equal(1, csvFile.numberOfRows(), “numberOfRows() must be 1 for line ending test, without extra CRLF”);
equal(1, csvFile.numberOfColumns(), “numberOfColumns() must be 1 for line ending test, without extra CRLF”);
data = std::stringstream{R”:(Header1
Field1
):”};
csvFile = CsvFile{data};
equal(1, csvFile.numberOfRows(), “numberOfRows() must be 1 for line ending test, WITH extra CRLF”);
equal(1, csvFile.numberOfColumns(), “numberOfColumns() must be 1 for line ending test, WITH extra CRLF”);
return passFailText();
}
std::string Testing::testDoubleQuotedFields()
{
std::stringstream data{R”:(“Header,1″,”Header,2″,”Header,3″,” Header 4 ”
“Field,1″,”Field,2″,”Field,3″,” Field 4 “):”};
CsvFile csvFile{data};
equal(1, csvFile.numberOfRows(), “numberOfRows() must indicate 1, as the header + 1 row is present (double quote test)”);
equal(4, csvFile.numberOfColumns(), “numberOfColumns() must indicate 4 columns for the four fields (double quote test)”);
equal
equal
equal
equal
equal
equal
equal
equal
data = std::stringstream{R”:( “Header1”
“Field1″):”};
csvFile = CsvFile{data};
equal(-1, csvFile.numberOfRows(), “numberOfRows() must indicate load failure for whitespace outside double quotes (before quote)”);
equal(-1, csvFile.numberOfColumns(), “numberOfColumns() must indicate load failure for whitespace outside double quotes (before quote)”);
data = std::stringstream{R”:(“Header1” ,Header2
“Field1″ ,Field2):”};
csvFile = CsvFile{data};
equal(-1, csvFile.numberOfRows(), “numberOfRows() must indicate load failure for whitespace outside double quotes (after quote)”);
equal(-1, csvFile.numberOfColumns(), “numberOfColumns() must indicate load failure for whitespace outside double quotes (after quote)”);
return passFailText();
}
std::string Testing::testDoubleQuotedFieldsMixedWithUnquoted()
{
std::stringstream data{R”:(“Header,1″,Header2,”Header,3”,Header4
“Field,1″,Field2,”Field,3″,Field4):”};
CsvFile csvFile{data};
equal(1, csvFile.numberOfRows(), “numberOfRows() must indicate 1, as the header + 1 row is present (mixed test)”);
equal(4, csvFile.numberOfColumns(), “numberOfColumns() must indicate 4 columns for the three fields (mixed test)”);
equal
equal
equal
equal
equal
equal
equal
equal
return passFailText();
}
std::string Testing::testReplacementOfBlackslashNInQuotedFieldsWithNewline()
{
std::stringstream data{R”:(“Header\n1″,”He\nader\n2”,Header\n3
“Field\n1″,”Fi\neld\n2″,Field\n3):”};
CsvFile csvFile{data};
equal
equal
equal
equal
equal
equal
return passFailText();
}
std::string Testing::testDoubleQuotesWithinFields()
{
std::stringstream data{R”:(“Header””1”
“Field””1″):”};
CsvFile csvFile{data};
equal(1, csvFile.numberOfRows(), “numberOfRows() must indicate 1, as the header + 1 row is present (double quote test)”);
equal(1, csvFile.numberOfColumns(), “numberOfColumns() must indicate 4 columns for the three fields (double quote test)”);
equal
equal
data = std::stringstream{R”:(“Header””,””1″
“Field””,””1″):”};
csvFile = CsvFile{data};
equal(1, csvFile.numberOfRows(), “numberOfRows() must indicate 1, as the header + 1 row is present (double quote test with comma)”);
equal(1, csvFile.numberOfColumns(), “numberOfColumns() must indicate 4 columns for the three fields (double quote test with comma)”);
equal
equal
return passFailText();
}
std::string Testing::testReadingCsvDataFromFile()
{
std::ifstream dataFile{“creature_types_sample.csv”};
CsvFile csvFile{dataFile};
dataFile.close(); // Ensure you close the file stream after loading the data
equal(3, csvFile.numberOfRows(), “numberOfRows() the example file contains three rows”);
equal(8, csvFile.numberOfColumns(), “numberOfColumns() the example file contains 8 columns”);
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
equal
return passFailText();
}
#include “wall.h”
using namespace core::dungeon;
Wall::Wall()
{
}
#include “game.h”
#include “weapons.h”
#include
#include
using namespace core::weapons;
/* ——————————————————————————
* Weapon member implementations
* —————————————————————————–*/
Weapon::Weapon()
{
}
Fists::Fists()
{
}
Boomerang::Boomerang()
{
}
ShortSword::ShortSword()
{
}
BattleAxe::BattleAxe()
{
}
WizardsStaff::WizardsStaff()
{
}
MagicWand::MagicWand()
{
}
/* ——————————————————————————
* Enchantment member implementations
* —————————————————————————–*/
Enchantment::Enchantment()
{
}
FlameEnchantment::FlameEnchantment()
{
}
ElectricityEnchantment::ElectricityEnchantment()
{
}
HealingEnchantment::HealingEnchantment()
{
}
VampirismEnchantment::VampirismEnchantment()
{
}
#ifndef BASICDUNGEON_H
#define BASICDUNGEON_H
#include “commondungeon.h”
namespace core {
namespace dungeon {
// TODO: define component classes spcific to the BasicDungeon type
/**
* @brief TODO The BasicDungeon class
*/
class BasicDungeon
{
public:
BasicDungeon();
};
/**
* @brief TODO The RockChamber class
*/
class RockChamber
{
public:
RockChamber();
};
/**
* @brief TODO The QuartzChamber class
*/
class QuartzChamber
{
public:
QuartzChamber();
};
/**
* @brief TODO The BasicWall class
*/
class RockWall
{
public:
RockWall();
};
} // namespace dungeon
} // namespace core
#endif // BASICDUNGEON_H
#ifndef CHARACTER_H
#define CHARACTER_H
#include
namespace core {
// TODO: define Character class.
// There is some example code in here, but it can be modified if desired.
/**
* @brief TODO The Complete the Character class, following is just a small example
*/
class Character
{
public:
Character(const std::string &name);
const std::string& name() const;
private:
std::string _name;
};
} // namespace core
std::ostream& operator<<(std::ostream &stream, const core::Character &character);
#endif // CHARACTER_H
#ifndef COMMONDUNGEON_H
#define COMMONDUNGEON_H
#include "dungeon.h"
#include "room.h"
#include "wall.h"
#include "door.h"
namespace core {
namespace dungeon {
// TODO: define concrete components classes common to all dungeon types
/**
* @brief TODO The OpenDoorway class
*/
class OpenDoorway
{
public:
OpenDoorway();
};
} // namespace dungeon
} // namespace core
#endif // COMMONDUNGEON_H
#ifndef CREATURE_H
#define CREATURE_H
#include
namespace core {
namespace creatures {
// TODO: define Creature class and the its concrete subclasses.
// There is some example code in here, but it can be modified if desired.
/**
* @brief TODO The Creature class
*/
class Creature
{
public:
Creature(const std::string &name);
const std::string& name() const;
private:
std::string _name;
};
} // namespace creatures
} // namespace core
#endif // CREATURE_H
#ifndef CSVFILE_H
#define CSVFILE_H
#include
#include
namespace data {
/**
* @brief The CsvFile class reads CSV data from a stream and makes it
* available to the application on a read-only basis.
*
* CSV Files contain tabular data in rows and columns according to the
* format defined by RFC 4180 [https://tools.ietf.org/html/rfc4180].
* (Ignore the requirement for fields contianign CRLF. We can assume
* that there are no CRLF in the input files.)
*
* The data is accessed through a simple inteface using row and column
* indices, both of which start at 1 (not zero). The interface also
* provides access to the header data, i.e., the column names.
*
* The CSV data is loaded in the constructor, from an input stream.
* This allows the data to be read from file or any other source connected
* to a stream.
*
* You will need to implement this class according to the provided interface.
* There is a set of tests provided in ‘testing.cpp’ for you to check that
* your implementation conforms. Be sure to enable testing in ‘testingsettings.h’
* to run the test suite and check your implementation.
*/
class CsvFile
{
public:
/**
* @brief CsvFile constructor, initialises internal data structures
* with CSV content from the input stream.
*
* Assumes the first row is a header row. If the input contains no
* content, the CsvFile is considered to have failed to load.
*
* @param input the stream from which to read the data
*/
CsvFile(std::istream &input);
/**
* @brief numberOfColumns Returns the number of columns in the CSV file,
* or -1 if the data failed to load.
*
* @return number of columns or -1
*/
int numberOfColumns() const;
/**
* @brief numberOfRows returns the number of rows in the CSV file,
* or -1 if the data failed to load.
*
* The header row is NOT included in the count of rows.
*
* @return number of rows or -1
*/
int numberOfRows() const;
/**
* @brief at Returns the content of the cell at the given row, column.
*
* Row indices start at 1, column indices start at 1.
* Returns an empty string if the CSV file failed to load or if row/column
* is out of range.
*
* @param row the row from which to retrieve the data
* @param column the column from whcih to retrieve the data
* @return the cell data at row, column
*/
std::string at(int row, int column) const;
/**
* @brief headerAt Returns the column name at the given index.
*
* Column indices start at 1.
* Returns an empty string if the CSV file failed to load or if column
* is out of range.
*
* @param column the index of the column
* @return the column name
*/
std::string headerAt(int column) const;
/**
* @brief columnIndexOf Returns the column index for the given column name.
*
* Returns -1 if the CSV file faild to load.
* Column indices start at 1.
*
* @param columnName the name of the column
* @return the index of the named column, or -1
*/
int columnIndexOf(const std::string &columnName) const;
};
} // namespace data
#endif // CSVFILE_H
#ifndef DOOR_H
#define DOOR_H
namespace core {
namespace dungeon {
/**
* @brief TODO The Door class
*/
class Door
{
public:
Door();
};
} // namespace dungeon
} // namespace core
#endif // DOOR_H
#ifndef DUNGEON_H
#define DUNGEON_H
#include “room.h”
#include