Gamified input-output tables (no GUI).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

123 lines
3.2 KiB

const std = @import("std");
pub const Range = struct {
min: f32 = 0,
max: f32 = 1,
inline fn l(self: *const @This(), r: f32) f32 {
return lerp(self.min, self.max, r);
}
pub inline fn get(self: *const @This(), rand: std.rand.Random) f32 {
const r = rand.float(f32);
return self.l(r);
}
pub inline fn int(
self: *const @This(),
comptime Type: type,
rand: std.rand.Random,
) Type {
return @as(Type, @intFromFloat(self.get(rand)));
}
pub inline fn norm(self: *const @This(), rand: std.rand.Random) f32 {
return normRange(rand, self.min, self.max);
}
};
pub inline fn lerp(min: f32, max: f32, r: f32) f32 {
return @mulAdd(f32, (max - min), r, min);
}
pub inline fn lerpInt(comptime Type: type, min: f32, max: f32, r: f32) Type {
return @as(f32, @intFromFloat(lerp(min, max, r)));
}
pub inline fn norm(rand: std.rand.Random, median: f32, dev: f32) f32 {
const r = rand.floatNorm(f32) * dev + median;
return std.math.clamp(r, 0, 1);
}
pub inline fn oneNorm(rand: std.rand.Random) f32 {
return norm(rand, 0.5, 0.2);
}
pub inline fn biasNorm(rand: std.rand.Random, bias: f32) f32 {
return norm(rand, (0.5 + bias) / 2, 0.2);
}
pub inline fn normRange(rand: std.rand.Random, min: f32, max: f32) f32 {
const r = oneNorm(rand);
return lerp(min, max, r);
}
pub inline fn randomItem(
comptime Type: type,
rand: std.rand.Random,
slices: []const []const Type,
) Type {
var limit: usize = 0;
for (slices) |slice| {
limit += slice.len;
}
var index = rand.uintLessThan(usize, limit);
for (slices) |slice| {
if (index >= slice.len) {
index -= slice.len;
} else {
return slice[index];
}
}
return undefined;
}
pub fn readFileAlloc(alloc: std.mem.Allocator, path: []const u8) ![]const u8 {
const max_size = 1024 * 1024 * 12;
return try std.fs.cwd().readFileAlloc(alloc, path, max_size);
}
pub fn free(allocator: std.mem.Allocator, obj: anytype) void {
const Type = @TypeOf(obj);
switch (@typeInfo(Type)) {
.Array => for (obj) |item| {
free(allocator, item);
},
.Struct => |info| inline for (info.fields) |field| {
free(allocator, @field(obj, field.name));
},
.Union => |info| if (info.tag_type) |Tag| {
inline for (info.fields) |field| {
if (obj == @field(Tag, field.name)) {
free(allocator, @field(obj, field.name));
}
}
},
.Pointer => |info| switch (info.size) {
.Slice => {
if (Type == []const u8) {
allocator.free(obj);
} else {
for (obj) |item| {
free(allocator, item);
}
allocator.free(obj);
}
},
.One => {
free(allocator, obj.*);
allocator.destroy(obj);
},
else => {},
},
.Optional => {
if (obj) |v| {
free(allocator, v);
}
},
else => {},
}
}