switch to zig build system and add conways game of life

This commit is contained in:
Squibid 2025-12-23 12:39:16 -05:00
parent 408de3a337
commit f219f0c5ce
Signed by: squibid
GPG key ID: BECE5684D3C4005D
12 changed files with 227 additions and 73 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
compile_commands.json compile_commands.json
.cache .cache
.zig-cache
zig-out

9
.gitmodules vendored
View file

@ -1,9 +0,0 @@
[submodule "lib/log.c"]
path = lib/log.c
url = https://github.com/rxi/log.c
[submodule "lib/ds"]
path = lib/ds
url = https://git.squi.bid/squibid/ds
[submodule "lib/cargs"]
path = lib/cargs
url = https://github.com/likle/cargs

81
build.zig Normal file
View file

@ -0,0 +1,81 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const ds = b.dependency("ds", .{});
const cargs = b.dependency("cargs", .{});
const log = b.dependency("log.c", .{});
const exe = b.addExecutable(.{
.name = "wom",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
const games = b.addLibrary(.{
.name = "games",
.linkage = .static,
.root_module = b.createModule(.{
.root_source_file = b.path("src/subcmds/games.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
games.pie = true;
exe.root_module.addCSourceFiles(.{
.files = &.{
"src/main.c",
"src/conf.c",
"src/api.c",
"src/subcmds/clock.c",
"src/subcmds/dev.c",
"src/subcmds/motd.c",
"src/subcmds/project.c",
"src/subcmds/subcmds.c",
"src/lua/wom.c",
"src/lua/wom_fs.c",
},
.flags = &.{
"-DVERSION=\"hi\"",
"-std=c23",
"-D_GNU_SOURCE",
"-MJ compile_commands.json",
}
});
exe.root_module.linkLibrary(games);
exe.root_module.linkSystemLibrary("lua", .{});
exe.root_module.addIncludePath(b.path("include"));
exe.root_module.addLibraryPath(ds.path("."));
exe.root_module.addLibraryPath(cargs.path("src"));
exe.root_module.addLibraryPath(log.path("src"));
exe.addCSourceFile(.{ .file = ds.builder.path("./ds.c") });
exe.addCSourceFile(.{ .file = cargs.builder.path("src/cargs.c") });
exe.addCSourceFile(.{ .file = log.builder.path("./src/log.c") });
exe.root_module.addIncludePath(ds.path("."));
exe.root_module.addIncludePath(cargs.path("include"));
exe.root_module.addIncludePath(log.path("src"));
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

20
build.zig.zon Normal file
View file

@ -0,0 +1,20 @@
.{
.name = .womblic,
.version = "0.15.2",
.dependencies = .{
.ds = .{
.url = "git+https://git.squi.bid/squibid/ds#758edf9d3049c61aa0036c8239f9fa922905a387",
.hash = "N-V-__8AALpEAACaGIC6yceiHvUlUJ-DX3QMaZ9I6uiDgclh",
},
.cargs = .{
.url = "git+https://github.com/likle/cargs#0698c3f90333446d0fc2745c1e9ce10dd4a9497a",
.hash = "N-V-__8AAPD5AQDYgLFfeI5K_q70qlurwjhY_e403fseMs3O",
},
.@"log.c" = .{
.url = "git+https://github.com/rxi/log.c#f9ea34994bd58ed342d2245cd4110bb5c6790153",
.hash = "N-V-__8AAJ8jAAAVkKD-RFvNLcnmi3SJZWigTFePQTb0sG-u",
},
},
.paths = .{""},
.fingerprint = 0x9cc5d26802316aa6,
}

View file

@ -9,4 +9,5 @@ void timer_subcmd(void *, int argc, char *argv[]);
void stopwatch_subcmd(void *, int argc, char *argv[]); void stopwatch_subcmd(void *, int argc, char *argv[]);
void subcmds_dev(void *, int argc, char *argv[]); void subcmds_dev(void *, int argc, char *argv[]);
void motd_subcmd(void *, int argc, char *argv[]); void motd_subcmd(void *, int argc, char *argv[]);
void games_subcmd(void *, int argc, char *argv[]);
void subcmds_subcmd(void *, int argc, char *argv[]); void subcmds_subcmd(void *, int argc, char *argv[]);

@ -1 +0,0 @@
Subproject commit 0698c3f90333446d0fc2745c1e9ce10dd4a9497a

1
lib/ds

@ -1 +0,0 @@
Subproject commit 5e4ae41113e63004bd131010853e5265b31302d3

@ -1 +0,0 @@
Subproject commit f9ea34994bd58ed342d2245cd4110bb5c6790153

View file

@ -1,60 +0,0 @@
project('womblic', 'c',
version: '0.0.1',
license: 'GPLv3')
add_project_arguments([
'-DVERSION="@0@"'.format(meson.project_version()),
'-DLOG_USE_COLOR' # enable colored logs
], language: 'c')
# get all the source files for the executable
luafiles = files(
'src/lua/wom.c',
'src/lua/wom_fs.c'
)
subcmds = files(
'src/subcmds/clock.c',
'src/subcmds/dev.c',
'src/subcmds/motd.c',
'src/subcmds/project.c',
'src/subcmds/subcmds.c',
)
srcfiles = files(
'src/main.c',
'src/api.c',
'src/conf.c'
) + luafiles + subcmds
cc = meson.get_compiler('c')
math_dep = cc.find_library('m', required: true)
# build the executable
executable('wom', srcfiles,
dependencies: [
dependency('lua', version: '>=5.1 <6.0'),
math_dep,
],
include_directories: [
include_directories('include'),
include_directories('lib/log.c/src'),
include_directories('lib/ds'),
include_directories('lib/cargs/include'),
],
link_with: [
static_library('ds', 'lib/ds/ds.c',
include_directories: 'lib/ds'),
static_library('log.c', 'lib/log.c/src/log.c',
include_directories: 'lib/log.c/src'),
static_library('cargs', 'lib/cargs/src/cargs.c',
include_directories: 'lib/cargs/include'),
],
install: true
)
install_data('completions/_wom.zsh',
install_dir: '/usr/local/share/zsh/site-functions/'
)

View file

@ -100,6 +100,7 @@ main(int argc, char *argv[])
register_subcmd("stopwatch", stopwatch_subcmd, NULL); register_subcmd("stopwatch", stopwatch_subcmd, NULL);
register_subcmd("subcmds", subcmds_subcmd, NULL); register_subcmd("subcmds", subcmds_subcmd, NULL);
register_subcmd("dev", subcmds_dev, NULL); register_subcmd("dev", subcmds_dev, NULL);
register_subcmd("games", games_subcmd, NULL);
/* if the user didn't specify a config path */ /* if the user didn't specify a config path */
if (!config_path) { if (!config_path) {

View file

@ -344,7 +344,7 @@ stopwatch_subcmd(void *, int argc, char *argv[])
if (pfd.revents & POLLIN) { if (pfd.revents & POLLIN) {
read(pfd.fd, buf, PATH_MAX); read(pfd.fd, buf, PATH_MAX);
ds_dll_insert(laps, (void *)(long)i); ds_dll_append(laps, (void *)(long)i);
up++; up++;
} }

121
src/subcmds/games.zig Normal file
View file

@ -0,0 +1,121 @@
const std = @import("std");
const gpa = std.heap.page_allocator;
const Conway = struct {
generation: u64 = 0,
width: u64,
height: u64,
world: [][]*Cell,
const Cell = struct {
/// storage of neighbors
/// ? 0 ?
/// 1 x 2
/// ? 3 ?
/// instead of storing all 8 neighbors I've decided to contact them
/// through our other neighbors.
neighbors: [4]?*Cell = .{ null, null, null, null },
/// the state on the current generation
alive: bool = false,
/// the state on the next generation
will_live: bool = false,
};
pub fn init(width: u64, height: u64) !Conway {
var self: Conway = .{
.width = width,
.height = height,
.world = undefined,
};
// create the world and the cells
self.world = try gpa.alloc([]*Cell, width);
for (self.world, 0..) |col, i| {
self.world[i] = try gpa.alloc(*Cell, height);
for (col, 0..) |_, j| {
if (j >= height) break;
self.world[i][j] = try gpa.create(Cell);
}
}
// initialize all the cell properties
for (self.world, 0..) |col, i| for (col, 0..) |cell, j| {
// the top row has nothing above it
cell.neighbors[0] = if (j == 0) null else self.world[i][j - 1];
// the left column has nothing on the left
cell.neighbors[1] = if (i == 0) null else self.world[i - 1][j];
// the right row has nothing on the right
cell.neighbors[2] = if (i == width - 1) null else self.world[i + 1][j];
// the bottom row has nothing below it
cell.neighbors[3] = if (j == height - 1) null else self.world[i][j + 1];
cell.alive = false;
};
return self;
}
pub fn step(self: *Conway) void {
for (self.world) |col| for (col) |cell| {
var alive_neighbors: u4 = 0;
// count the neighbors
for (cell.neighbors, 0..) |n, i| {
if (n == null) continue;
if (i == 0 or i == 3) {
if (n.?.neighbors[1]) |nn| if (nn.alive) {
alive_neighbors += 1;
};
if (n.?.neighbors[2]) |nn| if (nn.alive) {
alive_neighbors += 1;
};
}
if (n.?.alive) alive_neighbors += 1;
}
// rules
if (cell.alive) {
cell.will_live = switch (alive_neighbors) {
2, 3 => true,
else => false
};
} else if (alive_neighbors == 3) cell.will_live = true;
};
for (self.world) |col| for (col) |cell| {
cell.alive = cell.will_live;
};
}
pub fn print(self: *Conway) void {
for (self.world) |col| {
for (col) |cell| {
std.debug.print("{s}", .{if (cell.alive) "x" else " "});
}
std.debug.print("\n", .{});
}
}
};
pub export fn games_subcmd(_: *anyopaque, argc: c_int, argv: [*c]u8) callconv(.c) void {
_ = argc;
_ = argv;
var con = Conway.init(40, 40) catch unreachable;
con.world[4][2].alive = true;
con.world[4][3].alive = true;
con.world[4][4].alive = true;
con.world[4][5].alive = true;
con.world[4][6].alive = true;
con.world[4][7].alive = true;
con.world[5][2].alive = true;
con.world[5][3].alive = true;
con.world[5][4].alive = true;
con.world[5][5].alive = true;
con.world[5][6].alive = true;
while (true) : (con.step()) {
con.print();
std.posix.nanosleep(0, 250000000);
std.debug.print("\x1B[{}A", .{con.height});
}
}