Skip to content

Instantly share code, notes, and snippets.

@santa4nt
Created July 22, 2015 01:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save santa4nt/05dbf19d00b6507100ed to your computer and use it in GitHub Desktop.
Save santa4nt/05dbf19d00b6507100ed to your computer and use it in GitHub Desktop.
#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);
}
}
}
#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_
#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];
}
}
#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) );
}
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