Skip to content

Instantly share code, notes, and snippets.

@mstum
Last active August 29, 2015 14:06
Show Gist options
  • Save mstum/f12b96bce8311d2f0883 to your computer and use it in GitHub Desktop.
Save mstum/f12b96bce8311d2f0883 to your computer and use it in GitHub Desktop.
CodeReview #62254 - Static Factory function and Lifetime questions
#include "Level.h"
#include <fstream>
#include <sstream>
std::string Level::GetName(){
// Should this return a Pointer?
return _name;
}
int Level::GetPlayerStartX() {
return _playerStartX;
}
int Level::GetPlayerStartY() {
return _playerStartY;
}
Tile* Level::GetTiles() {
return _tiles;
}
int GetArrayIndex(int line, int column){
return (line * Level::MaxCols) + column;
}
Level* Level::LoadFromFile(std::string fileName){
std::string line;
std::ifstream file (fileName.c_str());
// This news up a level and works with it as a pointer
// Do callers need to call delete on it? How would they know?
Level* level = new Level();
int numBoxes = 0;
int numTargets = 0;
bool playerStart = false;
int y = -1;
while (getline(file, line)) {
if(y == -1){
level->_name = line;
}
else if (y >= Level::MaxRows) {
// Is there a better way? Like C#'s string.Format()
std::ostringstream exceptionMessage;
exceptionMessage << "There are more than " << Level::MaxRows << " rows in the level.";
// I'm calling .str().c_str() - is that a possible leak?
throw std::exception(exceptionMessage.str().c_str());
}
else {
int lineLength = line.length();
if(lineLength> Level::MaxCols){
std::ostringstream exceptionMessage;
exceptionMessage << "There are more than " << Level::MaxCols << " tiles in a column.";
throw std::exception(exceptionMessage.str().c_str());
}
for (int x=0; x < Level::MaxCols; x++)
{
int ix = GetArrayIndex(y, x);
char c = ' ';
if(x < lineLength) {
c = line[x];
}
switch(c) {
case Level::FreeChar:
level->_tiles[ix] = TILE_FREE;
break;
case Level::BoxChar:
numBoxes++;
level->_tiles[ix] = TILE_BOX;
break;
case Level::BoxOnTargetChar:
numBoxes++;
numTargets++;
level->_tiles[ix] = TILE_BOXONTARGET;
break;
case Level::TargetChar:
numTargets++;
level->_tiles[ix] = TILE_TARGET;
break;
case Level::WallChar:
level->_tiles[ix] = TILE_WALL;
break;
case Level::StartChar:
if(playerStart) {
throw std::exception("There is more than 1 player start in the level.");
}
playerStart = true;
level->_playerStartX = x;
level->_playerStartY = y;
level->_tiles[ix] = TILE_FREE;
break;
default:
throw std::exception("Invalid Character in Level: " + c);
}
}
}
y++;
}
// Fill up any missing Rows
for(;y < Level::MaxRows; y++){
for(int x = 0; x < Level::MaxCols; x++){
int ix = GetArrayIndex(y, x);
level->_tiles[ix] = TILE_FREE;
}
}
if(numBoxes != numTargets)
{
std::ostringstream exceptionMessage;
exceptionMessage << "There are " << numBoxes << ", but " << numTargets << " in the level.";
throw std::exception(exceptionMessage.str().c_str());
}
return level;
}
Level::Level() {
_playerStartX = _playerStartY = 0;
_tiles = new Tile[TileCount];
}
Level::~Level(){
if(_tiles) {
// Since _tiles is an array, I need delete[] instead of delete?
delete[] _tiles;
}
}
#include <iostream>
#include "Tile.h"
class Level
{
public:
std::string GetName();
int GetPlayerStartX();
int GetPlayerStartY();
Tile* GetTiles();
// Static Factory Function - only way to instantiate
static Level* LoadFromFile(std::string fileName);
// Static Consts for external callers to know constraints
static const int MaxCols = 30;
static const int MaxRows = 20;
static const int TileCount = MaxCols * MaxRows;
~Level();
private:
// Private ctor to prevent instantiation
Level();
// An Array of TileCount tiles
Tile* _tiles;
int _playerStartX, _playerStartY;
std::string _name;
// Used by LoadFromFile - could possibly moved into that function?
static const char FreeChar = ' ';
static const char BoxChar = '+';
static const char BoxOnTargetChar = '*';
static const char TargetChar = '.';
static const char WallChar = '=';
static const char StartChar = 'x';
};
// Do I need to prevent multiple inclusion? In what situations?
#ifndef TILE
#define TILE
enum Tile { TILE_UNKNOWN, TILE_FREE, TILE_BOX, TILE_TARGET, TILE_WALL, TILE_BOXONTARGET };
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment