1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
const cfg = @import("config.zig");
const std = @import("std");
/// Generate the set of rules the particles will abide by
pub fn ruleMatrix(radius: bool, speed: bool) [cfg.colorAmnt][cfg.colorAmnt]f32 {
const seed = @as(u64, @truncate(@as(u128, @bitCast(std.time.nanoTimestamp()))));
var prng = std.Random.DefaultPrng.init(seed);
var rules: [cfg.colorAmnt][cfg.colorAmnt]f32 = undefined;
for (0..cfg.colorAmnt) |i| {
for (0..cfg.colorAmnt) |j| {
var val = prng.random().float(f32);
const isNeg = prng.random().uintAtMost(u8, 1);
if (isNeg == 1) val = 0 - val;
rules[i][j] = val;
}
if (radius)
cfg.radius[i] = @intCast(@abs(prng.random().intRangeAtMost(i32, cfg.minDistance+1, 100)));
if (speed)
cfg.speed[i] = prng.random().intRangeAtMost(i32, 1, 1000);
}
return rules;
}
/// Prints rules generated from ruleMatrix()
pub fn printRules(rules: [cfg.colorAmnt][cfg.colorAmnt]f32) void {
std.debug.print("\n| {s:^7} ", .{"Rules"});
for (0..cfg.colors.len) |c|
std.debug.print("| {s:^7} ", .{colorToString(c)});
std.debug.print("|\n", .{});
for (rules, 0..) |row, i| {
std.debug.print("| {s:^7} ", .{colorToString(i)});
for (row) |col|
std.debug.print("| {d:^7.1} ", .{col});
std.debug.print("|\n", .{});
}
}
/// Loads rules from a csv
pub fn loadRules(allocator: std.mem.Allocator, absolutePath: [:0]u8) !void {
var buffer: [256]u8 = undefined;
const file = try std.fs.openFileAbsoluteZ(absolutePath, .{ .mode = .read_only });
defer file.close();
var reader = file.reader(&buffer).interface;
for (&cfg.rules) |*row| {
for (row) |*col| {
const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
col.* = try std.fmt.parseFloat(f32, buf);
}
reader.toss(1);
}
for (&cfg.speed) |*s| {
const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
s.* = try std.fmt.parseInt(i32, buf, 10);
}
reader.toss(1);
for (&cfg.radius) |*r| {
const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
r.* = try std.fmt.parseInt(i32, buf, 10);
}
reader.toss(1);
{
const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
cfg.minDistance = try std.fmt.parseInt(i32, buf, 10);
}
{
const buf = try reader.takeDelimiterExclusive(',');
defer allocator.free(buf);
cfg.friction = try std.fmt.parseFloat(f32, buf);
}
}
/// Save rules to a csv
pub fn saveRules(absolutePath: [:0]u8) !void {
var buffer: [256]u8 = undefined;
const file = try std.fs.createFileAbsoluteZ(absolutePath, .{ .read = true });
defer file.close();
var writer = file.writer(&buffer).interface;
for (cfg.rules) |row| {
for (row) |col| {
try writer.print("{d:.3},", .{col});
}
_ = try writer.write("\n");
}
for (cfg.speed) |s| {
try writer.print("{d},", .{s});
}
_ = try writer.write("\n");
for (cfg.radius) |r| {
try writer.print("{d:.3},", .{r});
}
_ = try writer.write("\n");
try writer.print("{d:.3},", .{cfg.minDistance});
try writer.print("{d:.3},", .{cfg.friction});
}
/// Convert the color index to a string
pub inline fn colorToString(c: usize) []const u8 {
return switch (c) {
0 => "Red",
1 => "Green",
2 => "Blue",
3 => "Yellow",
4 => "Magenta",
5 => "Brown",
6 => "Orange",
7 => "Gray",
else => " ",
};
}
pub inline fn colorToStringZ(c: usize, comptime prepend: []const u8, comptime append: []const u8) [:0]const u8 {
return switch (c) {
0 => prepend ++ "Red" ++ append,
1 => prepend ++ "Green" ++ append,
2 => prepend ++ "Blue" ++ append,
3 => prepend ++ "Yellow" ++ append,
4 => prepend ++ "Magenta" ++ append,
5 => prepend ++ "Brown" ++ append,
6 => prepend ++ "Orange" ++ append,
7 => prepend ++ "Gray" ++ append,
else => " ",
};
}
|