Skip to content

Instantly share code, notes, and snippets.

@rofrol
Forked from doccaico/main.zig
Created August 8, 2022 14:47
Show Gist options
  • Save rofrol/d79e375bc9f9c4695beb0f6d7386c667 to your computer and use it in GitHub Desktop.
Save rofrol/d79e375bc9f9c4695beb0f6d7386c667 to your computer and use it in GitHub Desktop.
Conway's Game of Life
// Build: zig build-exe -O ReleaseFast --strip src/main.zig
// Run: zig build run -- -w 70 -h 40 -m "*" -s 0.07 -c 25
// Version: 0.10.0-dev.3475+b3d463c9e
// Date: 2022/08/08
const std = @import("std");
const mem = std.mem;
const fmt = std.fmt;
const os = std.os;
const Cgol = struct {
gpa: *std.mem.Allocator,
board: [][]u8,
subboard: [][]u8,
width: u32,
height: u32,
mark: u8,
sleep: u64,
cells: u32,
child_process: std.ChildProcess,
const clear_cmd = [_][]const u8{
"printf", "\\33c\\e[3J\\33c",
};
fn init(gpa: *std.mem.Allocator, width: u32, height: u32, mark: u8, sleep: f64, cells: u32) !Cgol {
var child_process = std.ChildProcess.init(&clear_cmd, gpa.*);
var board = try gpa.alloc([]u8, height + 2);
for (board) |*col| {
col.* = try gpa.alloc(u8, width + 2);
// zero clear
for (col.*) |*v| {
v.* = 0;
}
}
var subboard = try gpa.alloc([]u8, height + 2);
for (subboard) |*col| {
col.* = try gpa.alloc(u8, width + 2);
}
return Cgol{
.board = board,
.subboard = subboard,
.gpa = gpa,
.width = width,
.height = height,
.mark = mark,
.sleep = @floatToInt(u64, 1_000_000_000 * sleep),
.cells = cells,
.child_process = child_process,
};
}
fn deinit(self: *Cgol) void {
for (self.board) |*col| {
self.gpa.free(col.*);
}
self.gpa.free(self.board);
for (self.subboard) |*col| {
self.gpa.free(col.*);
}
self.gpa.free(self.subboard);
}
fn initBoard(self: *Cgol) !void {
var prng = std.rand.DefaultPrng.init(blk: {
var seed: u64 = undefined;
try os.getrandom(std.mem.asBytes(&seed));
break :blk seed;
});
const random = prng.random();
var y: usize = 1;
var x: usize = 1;
while (y < self.height + 1) : (y += 1) {
while (x < self.cells + 1) : (x += 1) {
self.board[y][x] = 1;
}
random.shuffle(u8, self.board[y][1..self.width]);
x = 1;
}
}
fn printBoard(self: *Cgol) !void {
const stdout = std.io.getStdOut().writer();
var ch: u8 = undefined;
var y: usize = 1;
var x: usize = 1;
while (y < self.height + 1) : (y += 1) {
while (x < self.width + 1) : (x += 1) {
ch = if (self.board[y][x] == 1) self.mark else ' ';
try stdout.writeByte(ch);
}
try stdout.writeByte('\n');
x = 1;
}
}
fn clear(self: *Cgol) !void {
_ = try self.child_process.spawnAndWait();
}
fn wait(self: *Cgol) void {
std.time.sleep(self.sleep);
}
fn nextGeneration(self: *Cgol) void {
var y: usize = 1;
var x: usize = 1;
while (y < self.height + 1) : (y += 1) {
while (x < self.width + 1) : (x += 1) {
self.subboard[y][x] = self.countNeighbors(y, x);
}
x = 1;
}
x = 1;
y = 1;
while (y < self.height + 1) : (y += 1) {
while (x < self.width + 1) : (x += 1) {
switch (self.subboard[y][x]) {
2 => {},
3 => self.board[y][x] = 1,
else => self.board[y][x] = 0,
}
}
x = 1;
}
}
fn countNeighbors(self: *Cgol, y: usize, x: usize) u8 {
// top-left
return self.board[y - 1][x - 1] +
// top-middle
self.board[y - 1][x] +
// top-right
self.board[y - 1][x + 1] +
// left
self.board[y][x - 1] +
// right
self.board[y][x + 1] +
// bottom-left
self.board[y + 1][x - 1] +
// bottom-middle
self.board[y + 1][x] +
// bottom-right
self.board[y + 1][x + 1];
}
};
fn help() void {
std.debug.print("Usage: zig build run -- -w 70 -h 40 -m \"*\" -s 0.07 -c 25\n", .{});
os.exit(0);
}
pub fn main() !void {
if (os.argv.len != 11 or os.argv.len == 1) {
help();
}
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = general_purpose_allocator.deinit();
var gpa = general_purpose_allocator.allocator();
var arg_iter = try std.process.argsWithAllocator(gpa);
defer arg_iter.deinit();
_ = arg_iter.next();
var width: u32 = undefined;
var height: u32 = undefined;
var mark: u8 = undefined;
var sleep: f64 = undefined;
var cells: u32 = undefined;
var in: i32 = 0;
if (mem.eql(u8, "-w", arg_iter.next().?)) {
width = try fmt.parseUnsigned(u32, arg_iter.next().?, 10);
in += 1;
}
if (mem.eql(u8, "-h", arg_iter.next().?)) {
height = try fmt.parseUnsigned(u32, arg_iter.next().?, 10);
in += 1;
}
if (mem.eql(u8, "-m", arg_iter.next().?)) {
mark = arg_iter.next().?[0];
in += 1;
}
if (mem.eql(u8, "-s", arg_iter.next().?)) {
sleep = try fmt.parseFloat(f64, arg_iter.next().?);
in += 1;
}
if (mem.eql(u8, "-c", arg_iter.next().?)) {
cells = try fmt.parseUnsigned(u32, arg_iter.next().?, 10);
in += 1;
}
if (in != 5) {
help();
}
// print("width: {}\n", .{width});
// print("height: {}\n", .{height});
// print("mark: {c}\n", .{mark});
// print("sleep: {d}\n", .{sleep});
// print("cells: {d}\n", .{cells});
var g: Cgol = try Cgol.init(&gpa, width, height, mark, sleep, cells);
defer g.deinit();
try g.initBoard();
while (true) {
try g.clear();
try g.printBoard();
g.nextGeneration();
g.wait();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment