Skip to content

Commit

Permalink
Merge pull request #73 from nhatdongdang/feature/chunk-iterator
Browse files Browse the repository at this point in the history
Chunk iterator and fix getter
  • Loading branch information
rozukke authored Aug 12, 2024
2 parents aa7394e + 2d99dd6 commit d0a4b5c
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 12 deletions.
91 changes: 91 additions & 0 deletions include/mcpp/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,97 @@ struct Coordinate {
* the base point they were gathered at and each other.
*/
struct Chunk {
/**
* @brief An iterator for the Chunk's 3D block data.
*
* This iterator allows for range-based for loops and standard iterator
* operations over the 3D block data stored within a Chunk. It provides a
* linear interface to traverse the 3D grid of blocks, enabling sequential
* access to the elements stored in the chunk.
*/
struct Iterator {
using value_type = BlockType;
using pointer = BlockType*;
using reference = BlockType&;

/**
* @brief Constructs an iterator at the given pointer position.
*
* @param ptr Pointer to the position in the height array.
*/
Iterator(pointer ptr) : m_ptr(ptr) {}

/**
* @brief Dereference the iterator to access the value at the current
* position.
*
* @return Reference to the current element.
*/
reference operator*() const { return *m_ptr; }

/**
* @brief Access the pointer to the current element.
*
* @return Pointer to the current element.
*/
pointer operator->() { return m_ptr; }

/**
* @brief Pre-increment operator. Advances the iterator to the next
* position.
*
* @return Reference to the updated iterator.
*/
Iterator& operator++() {
m_ptr++;
return *this;
}

/**
* @brief Post-increment operator. Advances the iterator to the next
* position.
*
* @param int Unused dummy parameter to differentiate from prefix
* increment.
* @return Iterator to the original position before incrementing.
*/
Iterator operator++(int) {
Iterator tmp = *this;
++(*this);
return tmp;
}

/**
* @brief Equality comparison operator.
*
* @param a First iterator to compare.
* @param b Second iterator to compare.
* @return true if both iterators point to the same position, false
* otherwise.
*/
friend bool operator==(const Iterator& a, const Iterator& b) {
return a.m_ptr == b.m_ptr;
};

/**
* @brief Inequality comparison operator.
*
* @param a First iterator to compare.
* @param b Second iterator to compare.
* @return true if iterators point to different positions, false
* otherwise.
*/
friend bool operator!=(const Iterator& a, const Iterator& b) {
return a.m_ptr != b.m_ptr;
};

private:
pointer m_ptr;
};

Iterator begin() { return Iterator(&raw_data[0]); }
Iterator end() { return Iterator(&raw_data[_x_len * _y_len * _z_len]); }

/**
* Initialized by copying from a flat vector of blocks
*/
Expand Down
6 changes: 3 additions & 3 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ BlockType Chunk::get(int x, int y, int z) {
throw std::out_of_range("Out of bounds Chunk access at " +
to_string(Coordinate(x, y, z)));
}
return raw_data[z + _z_len * (x + _y_len * y)];
return raw_data[y * _x_len * _z_len + x * _z_len + z];
}

BlockType Chunk::get_worldspace(const Coordinate& pos) {
Expand All @@ -108,8 +108,8 @@ BlockType Chunk::get_worldspace(const Coordinate& pos) {
to_string(array_pos) + " (world coordinate " +
to_string(pos) + " )");
}
return raw_data[array_pos.z +
_z_len * (array_pos.x + _y_len * array_pos.y)];
return raw_data[array_pos.y * _x_len * _z_len + array_pos.x * _z_len +
array_pos.z];
}

int Chunk::x_len() const { return this->_x_len; }
Expand Down
36 changes: 27 additions & 9 deletions test/minecraft_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,11 @@ TEST_CASE("Test the main mcpp class") {
}

TEST_CASE("getBlocks and Chunk operations") {

// Setup
Coordinate test_loc(100, 100, 100);
Coordinate loc1{100, 100, 100};
Coordinate loc2{110, 110, 110};
Coordinate loc2{110, 111, 112};

// Reset blocks that existed before
mc.setBlocks(loc1, loc2, Blocks::AIR);
Expand All @@ -145,22 +146,22 @@ TEST_CASE("getBlocks and Chunk operations") {

CHECK_EQ(data.base_pt(), loc1);
CHECK_EQ(data.x_len(), 11);
CHECK_EQ(data.y_len(), 11);
CHECK_EQ(data.z_len(), 11);
CHECK_EQ(data.y_len(), 12);
CHECK_EQ(data.z_len(), 13);

data = mc.getBlocks(loc2, loc1);

CHECK_EQ(data.base_pt(), loc1);
CHECK_EQ(data.x_len(), 11);
CHECK_EQ(data.y_len(), 11);
CHECK_EQ(data.z_len(), 11);
CHECK_EQ(data.y_len(), 12);
CHECK_EQ(data.z_len(), 13);
}

SUBCASE("Block accessing returns correct block using get()") {
CHECK_EQ(res.get(0, 0, 0), Blocks::GOLD_BLOCK);
CHECK_EQ(res.get(1, 1, 1), Blocks::BRICKS);
CHECK_EQ(res.get(1, 2, 3), Blocks::IRON_BLOCK);
CHECK_EQ(res.get(10, 10, 10), Blocks::DIAMOND_BLOCK);
CHECK_EQ(res.get(10, 11, 12), Blocks::DIAMOND_BLOCK);
}

SUBCASE("Block accessing returns correct block using get_worldspace()") {
Expand All @@ -174,13 +175,30 @@ TEST_CASE("getBlocks and Chunk operations") {

SUBCASE("Access out of bounds correctly throws") {
CHECK_THROWS(res.get(11, 0, 0));
CHECK_THROWS(res.get(0, 11, 0));
CHECK_THROWS(res.get(0, 0, 11));
CHECK_THROWS(res.get(0, 12, 0));
CHECK_THROWS(res.get(0, 0, 13));
CHECK_THROWS(res.get(-1, 0, 0));
CHECK_THROWS(res.get(0, -1, 0));
CHECK_THROWS(res.get(0, 0, -1));
CHECK_THROWS(res.get_worldspace(loc1 + Coordinate{-1, -1, -1}));
CHECK_THROWS(res.get_worldspace(loc1 + Coordinate{11, 11, 11}));
CHECK_THROWS(res.get_worldspace(loc1 + Coordinate{11, 12, 13}));
}

SUBCASE("Iterator") {
std::vector<BlockType> blocks;
for (int i = 0; i < res.y_len(); i++) {
for (int j = 0; j < res.x_len(); j++) {
for (int z = 0; z < res.z_len(); z++) {
blocks.push_back(res.get(j, i, z));
}
}
}

std::vector<BlockType> expected_blocks;
for (BlockType block : res) {
expected_blocks.push_back(block);
}
CHECK_EQ(blocks, expected_blocks);
}

mc.setBlock(test_loc, BlockType(0));
Expand Down

0 comments on commit d0a4b5c

Please sign in to comment.