8x8 grid
This commit is contained in:
48
include/Types/Grid8x8.h
Normal file
48
include/Types/Grid8x8.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// 8x8 bitset grid. Each bit represents a cell: bit index = (y << 3) | x.
|
||||
struct Grid8x8 final
|
||||
{
|
||||
struct Cell
|
||||
{
|
||||
int X, Y;
|
||||
};
|
||||
|
||||
class Iterator
|
||||
{
|
||||
uint64_t Remaining;
|
||||
|
||||
public:
|
||||
explicit Iterator(uint64_t bits) : Remaining(bits) {}
|
||||
|
||||
bool operator!=(const Iterator& other) const { return Remaining != other.Remaining; }
|
||||
|
||||
Cell operator*() const
|
||||
{
|
||||
int pos = __builtin_ctzll(Remaining);
|
||||
return { pos & 7, pos >> 3 };
|
||||
}
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
Remaining &= Remaining - 1; // clear lowest set bit
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() const { return Iterator(Bits); }
|
||||
Iterator end() const { return Iterator(0); }
|
||||
|
||||
// Number of filled cells.
|
||||
int Count() const { return __builtin_popcountll(Bits); }
|
||||
|
||||
bool Get(int x, int y) const { return (Bits >> ((y << 3) | x)) & 1; }
|
||||
void Set(int x, int y) { Bits |= uint64_t(1) << ((y << 3) | x); }
|
||||
void Clear(int x, int y) { Bits &= ~(uint64_t(1) << ((y << 3) | x)); }
|
||||
|
||||
uint64_t Bits = 0;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Grid8x8) == 8);
|
||||
167
tests/Util/test_Grid8x8.cpp
Normal file
167
tests/Util/test_Grid8x8.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include <doctest/doctest.h>
|
||||
#include <vector>
|
||||
#include "Types/Grid8x8.h"
|
||||
|
||||
TEST_SUITE("Grid8x8")
|
||||
{
|
||||
TEST_CASE("default construction - all cells empty")
|
||||
{
|
||||
Grid8x8 g;
|
||||
CHECK(g.Bits == 0);
|
||||
CHECK(g.Count() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Set and Get single cell")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(3, 5);
|
||||
CHECK(g.Get(3, 5));
|
||||
CHECK_FALSE(g.Get(0, 0));
|
||||
CHECK_FALSE(g.Get(3, 4));
|
||||
CHECK_FALSE(g.Get(4, 5));
|
||||
}
|
||||
|
||||
TEST_CASE("Clear cell")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(2, 2);
|
||||
CHECK(g.Get(2, 2));
|
||||
g.Clear(2, 2);
|
||||
CHECK_FALSE(g.Get(2, 2));
|
||||
CHECK(g.Count() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Set does not affect other cells")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(0, 0);
|
||||
g.Set(7, 7);
|
||||
CHECK(g.Get(0, 0));
|
||||
CHECK(g.Get(7, 7));
|
||||
CHECK_FALSE(g.Get(0, 7));
|
||||
CHECK_FALSE(g.Get(7, 0));
|
||||
CHECK(g.Count() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("Count matches number of set cells")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(0, 0);
|
||||
g.Set(1, 0);
|
||||
g.Set(0, 1);
|
||||
CHECK(g.Count() == 3);
|
||||
g.Clear(1, 0);
|
||||
CHECK(g.Count() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("Set same cell twice does not increase Count")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(4, 4);
|
||||
g.Set(4, 4);
|
||||
CHECK(g.Count() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("iterator - empty grid yields no cells")
|
||||
{
|
||||
Grid8x8 g;
|
||||
int count = 0;
|
||||
for (auto cell : g)
|
||||
++count;
|
||||
CHECK(count == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("iterator - single cell")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(3, 6);
|
||||
|
||||
std::vector<Grid8x8::Cell> cells;
|
||||
for (auto cell : g)
|
||||
cells.push_back(cell);
|
||||
|
||||
REQUIRE(cells.size() == 1);
|
||||
CHECK(cells[0].X == 3);
|
||||
CHECK(cells[0].Y == 6);
|
||||
}
|
||||
|
||||
TEST_CASE("iterator - corners")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(0, 0);
|
||||
g.Set(7, 0);
|
||||
g.Set(0, 7);
|
||||
g.Set(7, 7);
|
||||
|
||||
std::vector<Grid8x8::Cell> cells;
|
||||
for (auto cell : g)
|
||||
cells.push_back(cell);
|
||||
|
||||
REQUIRE(cells.size() == 4);
|
||||
|
||||
// Iterator visits in bit-index order (row-major: left-to-right, top-to-bottom)
|
||||
CHECK(cells[0].X == 0); CHECK(cells[0].Y == 0);
|
||||
CHECK(cells[1].X == 7); CHECK(cells[1].Y == 0);
|
||||
CHECK(cells[2].X == 0); CHECK(cells[2].Y == 7);
|
||||
CHECK(cells[3].X == 7); CHECK(cells[3].Y == 7);
|
||||
}
|
||||
|
||||
TEST_CASE("iterator - full grid visits all 64 cells")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Bits = ~uint64_t(0);
|
||||
|
||||
int count = 0;
|
||||
bool seen[8][8] = {};
|
||||
for (auto cell : g)
|
||||
{
|
||||
CHECK(cell.X >= 0); CHECK(cell.X < 8);
|
||||
CHECK(cell.Y >= 0); CHECK(cell.Y < 8);
|
||||
CHECK_FALSE(seen[cell.Y][cell.X]);
|
||||
seen[cell.Y][cell.X] = true;
|
||||
++count;
|
||||
}
|
||||
CHECK(count == 64);
|
||||
}
|
||||
|
||||
TEST_CASE("iterator count matches Count()")
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(1, 2);
|
||||
g.Set(3, 4);
|
||||
g.Set(5, 6);
|
||||
g.Set(7, 1);
|
||||
|
||||
int iterated = 0;
|
||||
for (auto cell : g)
|
||||
++iterated;
|
||||
|
||||
CHECK(iterated == g.Count());
|
||||
}
|
||||
|
||||
TEST_CASE("iterator - coordinates decode correctly for every cell")
|
||||
{
|
||||
for (int y = 0; y < 8; ++y)
|
||||
{
|
||||
for (int x = 0; x < 8; ++x)
|
||||
{
|
||||
Grid8x8 g;
|
||||
g.Set(x, y);
|
||||
|
||||
int count = 0;
|
||||
for (auto cell : g)
|
||||
{
|
||||
CHECK(cell.X == x);
|
||||
CHECK(cell.Y == y);
|
||||
++count;
|
||||
}
|
||||
CHECK(count == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("size is 8 bytes")
|
||||
{
|
||||
static_assert(sizeof(Grid8x8) == 8);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user