SubMatrixes

This commit is contained in:
2026-04-15 06:29:44 -05:00
parent 43129e95c7
commit 4bf8af7de5
+89 -27
View File
@@ -6,6 +6,12 @@ const Allocator = mem.Allocator;
pub const Point = struct {
x: usize,
y: usize,
/// index returns the index in a flat array of the point givent he
/// provided width.
pub fn index(self: *const Point, width: usize) usize {
return (self.y * width) + self.x;
}
};
/// Rect is a rectangle
@@ -18,32 +24,27 @@ pub const Rect = struct {
}
};
/// Area is the area
pub const Area = struct {
location: Point,
size: Rect,
};
/// Matrix is a part of the game board
pub fn Matrix(comptime T: type, size: Rect) type {
const MatrixRowIterator = RowIterator(T, size.width);
pub fn Matrix(comptime T: type) type {
return struct {
/// data is the game board itself.
data: []T,
///
size: Rect,
/// init creates the chunk, storing the bytes in memory.
pub fn initZero(gpa: Allocator) !@This() {
pub fn initZero(gpa: Allocator, size: Rect) !@This() {
const data = try gpa.alloc(T, size.area());
@memset(data, mem.zeroes(T));
return .{ .data = data };
return .{ .data = data, .size = size };
}
/// init creates the chunk, storing the bytes in memory.
pub fn init(gpa: Allocator, zero: T) !@This() {
pub fn init(gpa: Allocator, zero: T, size: Rect) !@This() {
const data = try gpa.alloc(T, size.area());
@memset(data, zero);
return .{ .data = data };
return .{ .data = data, .size = size };
}
/// deinit frees the memory utilized to create the chunk
@@ -53,18 +54,23 @@ pub fn Matrix(comptime T: type, size: Rect) type {
// set sets the value of the specified location in memory
pub fn set(self: *@This(), loc: Point, val: T) void {
const index = (size.width * loc.y) + loc.x;
const index = (self.size.width * loc.y) + loc.x;
self.data[index] = val;
}
// set sets the value of the specified location in memory
pub fn get(self: *const @This(), loc: Point) T {
const index = (size.width * loc.y) + loc.x;
const index = (self.size.width * loc.y) + loc.x;
return self.data[index];
}
pub fn row_iterator(self: *@This()) MatrixRowIterator {
return .init(self.data);
pub fn row_iterator(self: *@This()) RowIterator(T) {
return .init(self);
}
/// submatrix returns a [SubMatrix]
pub fn submatrix(self: *@This(), gpa: Allocator, loc: Point, area: Rect) !SubMatrix(T) {
return SubMatrix(T).init(gpa, self, loc, area);
}
};
}
@@ -72,25 +78,25 @@ pub fn Matrix(comptime T: type, size: Rect) type {
test "TestMatrix" {
const testing = std.testing;
var mat = try Matrix(u64, Rect{ .width = 10, .height = 10 }).initZero(testing.allocator);
var mat = try Matrix(u64).initZero(testing.allocator, Rect{ .width = 10, .height = 10 });
defer mat.deinit(testing.allocator);
mat.set(Point{ .x = 1, .y = 1 }, 100);
try testing.expectEqual(100, mat.get(Point{ .x = 1, .y = 1 }));
}
pub fn RowIterator(comptime T: type, width: usize) type {
pub fn RowIterator(comptime T: type) type {
return struct {
_index: usize,
/// data is a reference to the board game data, now we will return it as
/// each row
_data: []T,
fn init(data: []T) @This() {
return .{
._index = 0,
._data = data,
};
// The width of each row of data
_width: usize,
fn init(m: *Matrix(T)) @This() {
return .{ ._index = 0, ._data = m.data, ._width = m.size.width };
}
/// next returns the next row until we have exhausted the slice
@@ -100,8 +106,8 @@ pub fn RowIterator(comptime T: type, width: usize) type {
}
// increment a line at a time
defer self._index += width;
return self._data[self._index .. self._index + width];
defer self._index += self._width;
return self._data[self._index .. self._index + self._width];
}
};
}
@@ -109,7 +115,7 @@ pub fn RowIterator(comptime T: type, width: usize) type {
test "TestRowIterator" {
const testing = std.testing;
var chunk = try Matrix(usize, Rect{ .height = 10, .width = 10 }).initZero(testing.allocator);
var chunk = try Matrix(usize).initZero(testing.allocator, Rect{ .height = 10, .width = 10 });
defer chunk.deinit(testing.allocator);
for (0..10) |x| {
@@ -124,3 +130,59 @@ test "TestRowIterator" {
x += 1;
}
}
// SubMatrix is a subset of a matrix which you can traverse to
pub fn SubMatrix(comptime T: type) type {
return struct {
// Data is made up of different sections of the
_data: [][]T,
/// init takes the underlying data from the upstream matrix and creates
/// a submatrix of it
pub fn init(gpa: Allocator, m: *Matrix(T), loc: Point, size: Rect) !@This() {
var subData = try gpa.alloc([]T, size.height);
var index = loc.index(m.size.width);
for (0..size.height) |x| {
const ending_index = index + size.width;
subData[x] = m.data[index..ending_index];
index += m.size.width;
}
return .{
._data = subData,
};
}
pub fn deinit(self: *@This(), gpa: Allocator) void {
gpa.free(self._data);
}
/// get returns the type in the specified point
pub fn get(self: *const @This(), loc: Point) T {
return self._data[loc.y][loc.x];
}
/// set sets the value of the specified point
pub fn set(self: *@This(), loc: Point, val: T) void {
self._data[loc.y][loc.x] = val;
}
};
}
test "SubMatrix" {
const testing = std.testing;
// create our matrix and submatrix
var m = try Matrix(u64).initZero(testing.allocator, .{ .height = 10, .width = 10 });
defer m.deinit(testing.allocator);
var sub = try m.submatrix(testing.allocator, .{ .x = 4, .y = 4 }, .{ .height = 5, .width = 5 });
defer sub.deinit(testing.allocator);
// set the value
sub.set(.{ .x = 0, .y = 0 }, 100);
// it should be set in both locations
try testing.expectEqual(100, sub.get(.{ .x = 0, .y = 0 }));
try testing.expectEqual(100, m.get(.{ .x = 4, .y = 4 }));
}