change games into an arcade
This commit is contained in:
parent
f219f0c5ce
commit
70846f6283
7 changed files with 157 additions and 125 deletions
|
|
@ -21,7 +21,7 @@ pub fn build(b: *std.Build) void {
|
||||||
.name = "games",
|
.name = "games",
|
||||||
.linkage = .static,
|
.linkage = .static,
|
||||||
.root_module = b.createModule(.{
|
.root_module = b.createModule(.{
|
||||||
.root_source_file = b.path("src/subcmds/games.zig"),
|
.root_source_file = b.path("src/subcmds/arcade/arcade.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.link_libc = true,
|
.link_libc = true,
|
||||||
|
|
@ -48,7 +48,7 @@ pub fn build(b: *std.Build) void {
|
||||||
"-DVERSION=\"hi\"",
|
"-DVERSION=\"hi\"",
|
||||||
"-std=c23",
|
"-std=c23",
|
||||||
"-D_GNU_SOURCE",
|
"-D_GNU_SOURCE",
|
||||||
"-MJ compile_commands.json",
|
"-MJcompile_commands.json",
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,5 +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 arcade_subcmd(void *, int argc, char *argv[]);
|
||||||
void subcmds_subcmd(void *, int argc, char *argv[]);
|
void subcmds_subcmd(void *, int argc, char *argv[]);
|
||||||
|
|
|
||||||
|
|
@ -100,7 +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);
|
register_subcmd("arcade", arcade_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) {
|
||||||
|
|
|
||||||
5
src/subcmds/arcade/arcade.txt
Normal file
5
src/subcmds/arcade/arcade.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
@@@@@@ @@@@@@@ @@@@@@@ @@@@@@ @@@@@@@ @@@@@@@@
|
||||||
|
@@! @@@ @@! @@@ !@@ @@! @@@ @@! @@@ @@!
|
||||||
|
@!@!@!@! @!@!!@! !@! @!@!@!@! @!@ !@! @!!!:!
|
||||||
|
!!: !!! !!: :!! :!! !!: !!! !!: !!! !!:
|
||||||
|
: : : : : : :: :: : : : : :: : : : :: :::
|
||||||
13
src/subcmds/arcade/arcade.zig
Normal file
13
src/subcmds/arcade/arcade.zig
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Conway = @import("conway.zig");
|
||||||
|
|
||||||
|
pub export fn arcade_subcmd(_: *anyopaque, argc: c_int, argv: [*c]u8) callconv(.c) void {
|
||||||
|
_ = argc;
|
||||||
|
_ = argv;
|
||||||
|
|
||||||
|
// const title = @embedFile("arcade.txt");
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
const writer = std.fs.File.stdout().writer(&buf);
|
||||||
|
Conway.play(40, 40, @constCast(&writer.interface)) catch unreachable;
|
||||||
|
}
|
||||||
135
src/subcmds/arcade/conway.zig
Normal file
135
src/subcmds/arcade/conway.zig
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
// TODO: make interactive
|
||||||
|
const Conway = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const gpa = std.heap.page_allocator;
|
||||||
|
|
||||||
|
generation: u64 = 0,
|
||||||
|
width: u64,
|
||||||
|
height: u64,
|
||||||
|
world: [][]*Cell,
|
||||||
|
writer: *std.io.Writer,
|
||||||
|
|
||||||
|
const Cell = struct {
|
||||||
|
/// Technically we don't need to store any neighbors and we could just
|
||||||
|
/// check using the world, but that makes the logic far more terse.
|
||||||
|
///
|
||||||
|
/// 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, writer: *std.Io.Writer) !Conway {
|
||||||
|
var self: Conway = .{
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.world = undefined,
|
||||||
|
.writer = writer,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 deinit(self: *Conway) void {
|
||||||
|
for (self.world) |col| {
|
||||||
|
for (col) |cell| gpa.destroy(cell);
|
||||||
|
gpa.free(col);
|
||||||
|
}
|
||||||
|
gpa.free(self.world);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
// the living state must be applied after all the cells have been checked
|
||||||
|
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| {
|
||||||
|
try self.writer.print("{s}", .{if (cell.alive) "x" else " "});
|
||||||
|
}
|
||||||
|
_ = try self.writer.write("\n");
|
||||||
|
}
|
||||||
|
try self.writer.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play(width: u64, height: u64, writer: *std.Io.Writer) !void {
|
||||||
|
var con = try Conway.init(width, height, writer);
|
||||||
|
|
||||||
|
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()) {
|
||||||
|
try con.print();
|
||||||
|
std.posix.nanosleep(0, 250000000);
|
||||||
|
try con.writer.print("\x1B[{}A", .{con.height});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
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});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue