Created
July 22, 2015 01:49
-
-
Save santa4nt/05dbf19d00b6507100ed to your computer and use it in GitHub Desktop.
Same as https://gist.github.com/santa4nt/984c99819c0f79043dd5 but in C++11.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "LoGrid.hpp" | |
#if _DEBUG | |
void PrintLoGrid(const LoGrid &g) | |
{ | |
// TODO | |
} | |
#endif | |
void ApplyToggles(LoGrid &g, | |
const vector<LoGrid::Coord> &toggles_coords, | |
ApplyTogglesCallback cb /*= nullptr*/ | |
) | |
{ | |
for (const LoGrid::Coord &c : toggles_coords) | |
{ | |
g.Toggle(c); | |
if (cb) | |
{ | |
cb(g, c); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _LOGRID_H_DEFINED_ | |
#define _LOGRID_H_DEFINED_ | |
#include <vector> | |
#include <memory> | |
#include <utility> | |
#include <functional> | |
using std::vector; | |
using std::pair; | |
using std::function; | |
class LoGrid | |
{ | |
public: | |
using Coord = pair<unsigned int, unsigned int>; | |
LoGrid(size_t dim); | |
LoGrid(const vector<bool> &init_state); | |
size_t GetDim() const; | |
bool IsOff(unsigned int x, unsigned int y) const; | |
bool IsOff(const Coord &c) const; | |
bool IsOn(unsigned int x, unsigned int y) const; | |
bool IsOn(const Coord &c) const; | |
bool IsAllOff() const; | |
bool IsAllOn() const; | |
void Toggle(unsigned int x, unsigned int y); | |
void Toggle(const Coord &c); | |
private: // helper methods | |
inline void _VerifyCoord(const Coord &c) const; | |
inline unsigned int _Index(const Coord &c) const; | |
private: // states | |
size_t m_dim; | |
vector<bool> m_state; | |
}; | |
#if _DEBUG | |
void PrintLoGrid(const LoGrid &g); | |
#endif | |
using ApplyTogglesCallback = function<void(const LoGrid &, const LoGrid::Coord &)>; | |
/** | |
* Apply an ordered series of toggle coordinates to the given LoGrid. | |
* | |
* Optionally, a callback can be supplied, to be called with a reference to | |
* the grid itself, and the coordinate that has just been toggled; this is | |
* for the caller to check/query the state of the grid. | |
*/ | |
void ApplyToggles(LoGrid &g, | |
const vector<LoGrid::Coord> &toggles_coords, | |
ApplyTogglesCallback cb = nullptr | |
); | |
#endif//_LOGRID_H_DEFINED_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "LoGrid.h" | |
#include <cmath> | |
#include <exception> | |
using std::exception; | |
LoGrid::LoGrid(size_t dim) | |
: m_dim(dim), | |
m_state() | |
{ | |
if (dim == 0) | |
{ | |
throw exception(); | |
} | |
m_state.reserve(dim * dim); | |
m_state.insert(m_state.begin(), dim * dim, false); | |
} | |
LoGrid::LoGrid(const vector<bool> &init_state) | |
: m_dim(0), | |
m_state() | |
{ | |
bool isPerfectSquare = false; | |
size_t len = init_state.size(); | |
size_t dim = 0; | |
if (len == 0) | |
{ | |
throw exception(); | |
} | |
else if (len > 0) | |
{ | |
switch (static_cast<unsigned int>(len) & 0xF) | |
{ | |
case 0: | |
case 1: | |
case 4: | |
case 9: | |
{ | |
unsigned int tst = static_cast<unsigned int>(sqrt(len)); | |
isPerfectSquare = (tst * tst == len); | |
if (isPerfectSquare) | |
{ | |
dim = static_cast<size_t>(tst); | |
} | |
break; | |
} | |
default: | |
//isPerfectSquare = false; | |
break; | |
} | |
} | |
if (!isPerfectSquare) | |
{ | |
throw exception(); | |
} | |
m_dim = dim; | |
m_state = init_state; | |
} | |
size_t LoGrid::GetDim() const | |
{ | |
return m_dim; | |
} | |
void LoGrid::_VerifyCoord(const Coord &c) const | |
{ | |
if (c.first >= m_dim || c.second >= m_dim) | |
{ | |
throw exception(); | |
} | |
} | |
unsigned int LoGrid::_Index(const Coord &c) const | |
{ | |
_VerifyCoord(c); | |
return m_dim * c.first + c.second; | |
} | |
bool LoGrid::IsOff(unsigned int x, unsigned int y) const | |
{ | |
return IsOff({x, y}); | |
} | |
bool LoGrid::IsOff(const Coord &c) const | |
{ | |
return !m_state[_Index(c)]; | |
} | |
bool LoGrid::IsOn(unsigned int x, unsigned int y) const | |
{ | |
return IsOn({x, y}); | |
} | |
bool LoGrid::IsOn(const Coord &c) const | |
{ | |
return !IsOff(c); | |
} | |
bool LoGrid::IsAllOff() const | |
{ | |
for (bool b : m_state) | |
{ | |
if (b) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
bool LoGrid::IsAllOn() const | |
{ | |
for (bool b : m_state) | |
{ | |
if (!b) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
void LoGrid::Toggle(unsigned int x, unsigned int y) | |
{ | |
Toggle({x, y}); | |
} | |
void LoGrid::Toggle(const Coord &c) | |
{ | |
unsigned int index = _Index(c); | |
m_state[index] = !m_state[index]; | |
if (c.first > 0) // left neighbor | |
{ | |
index = _Index(Coord(c.first-1, c.second)); | |
m_state[index] = !m_state[index]; | |
} | |
if (c.first < m_dim - 1) // right neighbor | |
{ | |
index = _Index(Coord(c.first+1, c.second)); | |
m_state[index] = !m_state[index]; | |
} | |
if (c.second > 0) // top neighbor | |
{ | |
index = _Index(Coord(c.first, c.second-1)); | |
m_state[index] = !m_state[index]; | |
} | |
if (c.second < m_dim - 1) // bottom neighbor | |
{ | |
index = _Index(Coord(c.first, c.second+1)); | |
m_state[index] = !m_state[index]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "LoGrid.h" | |
#include <exception> | |
#define BOOST_TEST_DYN_LINK | |
#define BOOST_TEST_MODULE LoGridTest | |
#include <boost/test/unit_test.hpp> | |
using std::exception; | |
BOOST_AUTO_TEST_CASE( LoGrid_DimCtor_Constructed ) | |
{ | |
LoGrid g(5); | |
BOOST_REQUIRE_EQUAL( 5, g.GetDim() ); | |
BOOST_REQUIRE( g.IsAllOff() ); | |
BOOST_REQUIRE( !g.IsAllOn() ); | |
} | |
BOOST_AUTO_TEST_CASE( LoGrid_ZeroDimCtor_ThrowsException ) | |
{ | |
try | |
{ | |
LoGrid g(0); | |
BOOST_REQUIRE( false ); | |
} | |
catch (const exception&) | |
{ | |
BOOST_CHECK( true ); | |
} | |
} | |
BOOST_AUTO_TEST_CASE( LoGrid_InitStateCtor_Constructed ) | |
{ | |
const vector<bool> state(16, true); | |
LoGrid g(state); | |
BOOST_REQUIRE_EQUAL( 4, g.GetDim() ); | |
BOOST_REQUIRE( !g.IsAllOff() ); | |
BOOST_REQUIRE( g.IsAllOn() ); | |
} | |
BOOST_AUTO_TEST_CASE( LoGrid_InvalidInitStateCtor_ThrowsException ) | |
{ | |
const vector<vector<bool>> states | |
{ | |
vector<bool>(0, true), | |
vector<bool>(15, true), | |
vector<bool>(39, true) | |
}; | |
for (const vector<bool> &state : states) | |
{ | |
try | |
{ | |
LoGrid g(state); | |
BOOST_REQUIRE_MESSAGE( false, "Invalid size: " << state.size() ); | |
} | |
catch (const exception&) | |
{ | |
BOOST_CHECK( true ); | |
} | |
} | |
} | |
BOOST_AUTO_TEST_CASE( LoGrid_InvalidCoords_ThrowsException ) | |
{ | |
LoGrid g(5); | |
const vector<LoGrid::Coord> coords | |
{ | |
{5, 5}, | |
{4, 5}, | |
{5, 4} | |
}; | |
// capture methods of LoGrid:: which accept Coord value/reference, in lambdas | |
using UseCoordMethods = function<void(const LoGrid::Coord &)>; | |
const vector<UseCoordMethods> funcs | |
{ | |
[&g](const LoGrid::Coord &c) -> void | |
{ | |
g.IsOn(c); | |
}, | |
[&g](const LoGrid::Coord &c) -> void | |
{ | |
g.IsOff(c); | |
}, | |
[&g](const LoGrid::Coord &c) -> void | |
{ | |
g.Toggle(c); | |
} | |
}; | |
// for each invalid coordinate, try different methods of LoGrid:: | |
// above which accept a Coord value/reference | |
for (const LoGrid::Coord &c : coords) | |
{ | |
for (UseCoordMethods f : funcs) | |
{ | |
try | |
{ | |
f(c); | |
BOOST_REQUIRE_MESSAGE( false, | |
"Invalid coord: " << c.first << ", " << c.second ); | |
} | |
catch (const exception&) | |
{ | |
BOOST_CHECK( true ); | |
} | |
} | |
} | |
} | |
BOOST_AUTO_TEST_CASE( LoGrid_Toggle1_CheckState ) | |
{ | |
LoGrid g(5); | |
g.Toggle({1, 1}); | |
BOOST_REQUIRE( !g.IsAllOn() ); | |
BOOST_REQUIRE( !g.IsAllOff() ); | |
BOOST_REQUIRE( g.IsOn(1,1) ); | |
BOOST_REQUIRE( g.IsOn(0,1) ); | |
BOOST_REQUIRE( g.IsOn(2,1) ); | |
BOOST_REQUIRE( g.IsOn(1,0) ); | |
BOOST_REQUIRE( g.IsOn(1,2) ); | |
BOOST_REQUIRE( g.IsOff(0,0) ); | |
} | |
BOOST_AUTO_TEST_CASE( LoGrid_Toggle2_CheckState ) | |
{ | |
LoGrid g(5); | |
g.Toggle(4, 4); | |
BOOST_REQUIRE( !g.IsAllOn() ); | |
BOOST_REQUIRE( !g.IsAllOff() ); | |
BOOST_REQUIRE( g.IsOn(4,4) ); | |
BOOST_REQUIRE( g.IsOn(3,4) ); | |
BOOST_REQUIRE( g.IsOn(4,3) ); | |
BOOST_REQUIRE( g.IsOff(0,0) ); | |
BOOST_REQUIRE( g.IsOff(3,3) ); | |
} | |
BOOST_AUTO_TEST_CASE( ApplyToggles_InvalidCoord_ThrowsException ) | |
{ | |
LoGrid g(5); | |
const vector<LoGrid::Coord> coords | |
{ | |
{0, 0}, | |
{0, 1}, | |
{4, 5} | |
}; | |
try | |
{ | |
ApplyToggles(g, coords); | |
BOOST_REQUIRE( false ); | |
} | |
catch (const exception&) | |
{ | |
BOOST_CHECK( true ); | |
} | |
} | |
BOOST_AUTO_TEST_CASE( ApplyToggles_WithCallback_VerifyCallbackArgs ) | |
{ | |
LoGrid g(5); | |
const vector<LoGrid::Coord> coords | |
{ | |
{0, 0}, | |
{0, 1}, | |
{4, 4} | |
}; | |
unsigned int idx = 0; | |
ApplyTogglesCallback cb = | |
[&g, &idx, &coords](const LoGrid &cbg, const LoGrid::Coord &cbc) -> void | |
{ | |
BOOST_REQUIRE_EQUAL( &cbg, &g ); | |
BOOST_REQUIRE_EQUAL( coords[idx].first, cbc.first ); | |
BOOST_REQUIRE_EQUAL( coords[idx].second, cbc.second ); | |
++idx; | |
}; | |
ApplyToggles(g, coords, cb); | |
} | |
BOOST_AUTO_TEST_CASE( ApplyToggles_Coords1_VerifyFinalState ) | |
{ | |
LoGrid g(5); | |
const vector<LoGrid::Coord> coords | |
{ | |
{1, 1}, | |
{1, 2}, | |
{4, 4} | |
}; | |
ApplyToggles(g, coords); | |
BOOST_REQUIRE( g.IsOn(0,1) ); | |
BOOST_REQUIRE( g.IsOn(0,2) ); | |
BOOST_REQUIRE( g.IsOn(1,0) ); | |
BOOST_REQUIRE( g.IsOff(1,1) ); | |
BOOST_REQUIRE( g.IsOff(1,2) ); | |
BOOST_REQUIRE( g.IsOn(1,3) ); | |
BOOST_REQUIRE( g.IsOn(2,1) ); | |
BOOST_REQUIRE( g.IsOn(2,2) ); | |
BOOST_REQUIRE( g.IsOn(3,4) ); | |
BOOST_REQUIRE( g.IsOn(4,3) ); | |
BOOST_REQUIRE( g.IsOn(4,4) ); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CC = g++ | |
CFLAGS = -std=c++11 -Wall -g | |
LFLAGS = -lboost_unit_test_framework | |
DEFINES = -D_DEBUG | |
TARGET = LoGridTest | |
all: $(TARGET) | |
LoGridTest: LoGrid.o LoGridTest.o | |
$(CC) LoGrid.o LoGridTest.o $(LFLAGS) -o $(TARGET) | |
LoGrid.o: LoGrid.cpp LoGrid.hpp | |
$(CC) $(CFLAGS) $(DEFINES) -c LoGrid.cpp | |
LoGridTest.o: LoGridTest.cpp | |
$(CC) $(CFLAGS) $(DEFINES) -c LoGridTest.cpp | |
run: all | |
./$(TARGET) | |
valg: run | |
valgrind --leak-check=full -v ./$(TARGET) | |
clean: | |
rm -f *.o *.gch $(TARGET) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment