fixed sand bias and added progressive flow

This commit is contained in:
Dario48 2026-04-19 19:45:58 +02:00
commit 4ddb7e9efc
2 changed files with 87 additions and 27 deletions

View file

@ -2,6 +2,8 @@ const std = @import("std");
const sand = @import("sand");
const pow = std.math.pow;
const raylib = @import("raylib");
const raygui = @import("raygui");
@ -11,6 +13,8 @@ pub fn main(init: std.process.Init) !void {
var async: [screenHeight]std.Io.Future(void) = undefined;
var circleAsyncArray: ?[]std.Io.Future(void) = null;
var grid: sand.Grid = try .init(screenWidth, screenHeight, init.gpa);
defer grid.deinit(init.gpa);
// defer gridCopy.deinit(init.gpa);
@ -37,18 +41,25 @@ pub fn main(init: std.process.Init) !void {
raylib.initWindow(screenWidth, screenHeight, "sand");
defer raylib.closeWindow();
raylib.setTargetFPS(144 * 3);
var IndicatorPosition: raylib.Vector2 = .init(-100, -100);
var IndicatorSize: f32 = 40;
var IndicatorSizeDelta: f32 = 0;
const scrollSpeed = -3;
var placeChace: u8 = 250;
raylib.setTargetFPS(50);
var timeForUpdate: u64 = 0;
var timeForDraw: u64 = 0;
// init grid
var random = std.Random.DefaultPrng.init(@bitCast(std.Io.Timestamp.now(init.io, .real).toMicroseconds()));
for (0..300) |y| {
for (y..(600 - y)) |x| {
grid.arr[y][x] = .{ .alive = random.random().int(u8) > 179 };
}
}
// for (0..300) |y| {
// for (y..(600 - y)) |x| {
// grid.arr[y][x] = .{ .alive = random.random().int(u8) > 179 };
// }
// }
const texture: []raylib.Color = try init.gpa.alloc(raylib.Color, screenHeight * screenWidth);
defer init.gpa.free(texture);
@ -62,14 +73,6 @@ pub fn main(init: std.process.Init) !void {
};
const screenTexture = try raylib.loadTextureFromImage(screenImage);
var fps: struct {
total: f64,
count: f64,
} = .{
.total = 0,
.count = 0,
};
while (!raylib.windowShouldClose()) {
const updateTimer = std.Io.Clock.now(.awake, init.io);
try grid.updateAllConcurrent(init.gpa, init.io, &async);
@ -81,7 +84,10 @@ pub fn main(init: std.process.Init) !void {
const drawTimer = std.Io.Clock.now(.awake, init.io);
for (grid.arr, 0..) |line, y| {
for (line, 0..) |cell, x| {
texture[x + screenWidth * y] = if (cell.alive) .white else .black;
texture[x + screenWidth * y] = if (cell.alive)
.white
else
.black;
}
}
raylib.updateTexture(screenTexture, @ptrCast(texture));
@ -89,11 +95,46 @@ pub fn main(init: std.process.Init) !void {
timeForDraw += @intCast(drawTimer.durationTo(.now(init.io, .awake)).toMicroseconds());
fps.count += 1;
fps.total += @floatFromInt(raylib.getFPS());
std.log.info("fps: {}", .{raylib.getFPS()});
IndicatorPosition = raylib.getMousePosition();
IndicatorSizeDelta = 0;
IndicatorSizeDelta -= raylib.getMouseWheelMove() * scrollSpeed;
IndicatorSize += IndicatorSizeDelta;
if (IndicatorSizeDelta > 0) {
if (circleAsyncArray) |*arr| {
arr.* = try init.gpa.realloc(arr.*, @trunc(IndicatorSize * 2));
}
}
raylib.drawCircleV(IndicatorPosition, IndicatorSize, .alpha(.gray, 0.5));
if (raylib.isMouseButtonDown(.left)) {
if (placeChace > 170) placeChace -= 1;
if (circleAsyncArray) |_| {} else circleAsyncArray = try init.gpa.alloc(std.Io.Future(void), (@as(usize, @trunc(IndicatorPosition.y)) + @as(usize, @trunc(IndicatorSize)) - (@as(usize, @trunc(IndicatorPosition.y)) - @as(usize, @trunc(IndicatorSize)))));
for (@as(usize, @trunc(IndicatorPosition.x)) - @as(usize, @trunc(IndicatorSize))..@as(usize, @trunc(IndicatorPosition.x)) + @as(usize, @trunc(IndicatorSize)), 0..) |x, i| {
circleAsyncArray.?[i] = init.io.async((struct {
pub fn l(IP: raylib.Vector2, IS: f32, fx: usize, rand: *std.Random.DefaultPrng, gr: sand.Grid, pc: u8) void {
for (@as(usize, @trunc(IP.y)) - @as(usize, @trunc(IS))..@as(usize, @trunc(IP.y)) + @as(usize, @trunc(IS))) |y| {
const dx = @as(f32, @floatFromInt(fx)) - IP.x;
const dy = @as(f32, @floatFromInt(y)) - IP.y;
if (fx >= screenWidth or fx < 0 or y >= screenHeight or y < 0) {} else if (pow(f32, dx, 2) + pow(f32, dy, 2) <= pow(f32, IS, 2) and rand.random().int(u8) > pc)
gr.arr[y][fx].alive = true;
}
}
}).l, .{ IndicatorPosition, IndicatorSize, x, &random, grid, placeChace });
}
}
if (circleAsyncArray) |arr| {
for (arr) |*a| {
a.await(init.io);
}
}
if (raylib.isMouseButtonReleased(.left)) {
placeChace = 250;
init.gpa.free(circleAsyncArray.?);
circleAsyncArray = null;
}
// std.log.info("fps: {}", .{raylib.getFPS()});
}
std.log.debug("time for draw: {}, time for update: {}", .{ timeForDraw, timeForUpdate });
std.log.debug("median fps: {}", .{fps.total / fps.count});
}

View file

@ -67,25 +67,44 @@ pub const Grid = struct {
update(.{ .y = @truncate(y), .x = @truncate(x) }, self.*, newGrid);
}
}
switch (self.leaning) {
.Left => for (0..self.arr.len) |y| {
self.updateLineLeftBiased(newGrid, y);
},
.Right => for (0..self.arr.len) |y| {
self.updateLineRightBiased(newGrid, y);
},
}
self.deinit(allocator);
self.* = newGrid;
}
pub fn updateLineRightBiased(s: Grid, ng: Grid, fy: usize) void {
for (0..s.arr[fy].len) |x| {
update(.{ .y = @truncate(fy), .x = @truncate(x) }, s, ng);
}
}
pub fn updateLineLeftBiased(s: Grid, ng: Grid, fy: usize) void {
for (0..s.arr[fy].len) |x| {
update(.{ .y = @truncate(fy), .x = @truncate((s.arr[fy].len - x) - 1) }, s, ng);
}
}
pub fn updateAllConcurrent(self: *Grid, allocator: std.mem.Allocator, io: std.Io, async: []std.Io.Future(void)) (std.mem.Allocator.Error || std.Io.ConcurrentError)!void {
var newGrid: Grid = try .init(self.max.x + 1, self.max.y + 1, allocator);
newGrid.leaning = self.leaning.opposite();
for (0..self.arr.len) |y| {
async[y] = try io.concurrent((struct {
pub fn updateLine(s: Grid, ng: Grid, fy: usize) void {
for (0..s.arr[fy].len) |x| {
update(.{ .y = @truncate(fy), .x = @truncate(x) }, s, ng);
}
}
}).updateLine, .{ self.*, newGrid, y });
switch (self.leaning) {
.Left => for (0..self.arr.len) |y| {
async[y] = try io.concurrent(Grid.updateLineLeftBiased, .{ self.*, newGrid, y });
},
.Right => for (0..self.arr.len) |y| {
async[y] = try io.concurrent(Grid.updateLineRightBiased, .{ self.*, newGrid, y });
},
}
for (async) |*a| {
a.await(io);
}