Donut.zig but not a donut yet

Hello.

This is the code for a donut.zig , ported from a Rust version. It works, but it isn’t formatted like a donut yet.

const out = @import("std").io.getStdOut().writer();
pub fn main() !void {
    var a: f64 = 0;
    var b: f64 = 0;
    const s = [_]u8{ '.', ',', '-', '~', ':', ';', '=', '!', '*', '#', '$', '@' }; //
    try out.writeAll("\x1B[2J");
    while (true) {
        var b2: [1768]u8 = @splat(' ');
        var z: [1768]f64 = @splat(0);
        for (0..628) |j| if (j % 7 == 0) for (0..628) |i| if (i % 2 == 0) {
            const i_f: f64 = @floatFromInt(i);
            const j_f: f64 =
                @floatFromInt(j);
            const si = @sin(i_f / 100.0);
            const ci = @cos(i_f / 100.0);
            const sj = @sin(j_f / 100.0);
            const cj = @cos(j_f / 100.0);
            const cj2 = cj + 2.0;
            const sa = @sin(a);
            const ca = @cos(a);

            const sb = @sin(b);
            const cb = @cos(b);
            const m = 1.0 / (si * cj2 * sa + sj * ca + 5.0);
            const t = si * cj2 * ca - sj * sa;
            const x = 40.0 + 30.0 * m * (ci * cj2 * cb - t * sb);
            const y = 12.0 + 15.0 * m * (ci * cj2 * sb + t * cb);
            const o = @as(usize, @intFromFloat(x)) + 80 * @as(usize, @intFromFloat(y));
            const n = 8.0 * (((sj * sa - si * cj * ca) * cb) - (si * cj * sa) - (sj * ca) - (ci * cj * sb));
            if (22.0 > y and y > 0.0 and x > 0.0 and 80.0 > x and m > z[o]) {
                z[o] = m;
                const nidx: usize = if (n <= 0.0) 0 else @intFromFloat(n);
                b2[o] = s[nidx];
            }
        };
        try out.writeAll("\x1b[H");
        for (0..1760) |k| if (k % 80 != 0) try out.print("{c}", .{b2[k]}) else try out.writeAll("\n");
        a += 0.04;
        b += 0.02;
    }
}

Sadly, that doesn’t work on Windows. (If you care! :upside_down_face:)

            ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
donut.zig:1:49: note: initializer of container-level variable must be comptime-known
const out = @import("std").io.getStdOut().writer();
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
1 Like

Nice work!
I would also consider adding buffering to the writer, even tho it adds more code, you will sky rocket in performance (try this and see how much it sped up).

Your implementation, with no other changes than buffering:
(also solves windows problem @phatchman mentioned, windows has only runtime known stdout file descriptor)

const io = @import("std").io;
pub fn main() !void {
    var buffered = io.bufferedWriter(io.getStdOut().writer());
    const out = buffered.writer();
    var a: f64 = 0;
    var b: f64 = 0;
    const s = [_]u8{ '.', ',', '-', '~', ':', ';', '=', '!', '*', '#', '$', '@' }; //
    try out.writeAll("\x1B[2J");
    while (true) {
        var b2: [1768]u8 = @splat(' ');
        var z: [1768]f64 = @splat(0);
        for (0..628) |j| if (j % 7 == 0) for (0..628) |i| if (i % 2 == 0) {
            const i_f: f64 = @floatFromInt(i);
            const j_f: f64 =
                @floatFromInt(j);
            const si = @sin(i_f / 100.0);
            const ci = @cos(i_f / 100.0);
            const sj = @sin(j_f / 100.0);
            const cj = @cos(j_f / 100.0);
            const cj2 = cj + 2.0;
            const sa = @sin(a);
            const ca = @cos(a);

            const sb = @sin(b);
            const cb = @cos(b);
            const m = 1.0 / (si * cj2 * sa + sj * ca + 5.0);
            const t = si * cj2 * ca - sj * sa;
            const x = 40.0 + 30.0 * m * (ci * cj2 * cb - t * sb);
            const y = 12.0 + 15.0 * m * (ci * cj2 * sb + t * cb);
            const o = @as(usize, @intFromFloat(x)) + 80 * @as(usize, @intFromFloat(y));
            const n = 8.0 * (((sj * sa - si * cj * ca) * cb) - (si * cj * sa) - (sj * ca) - (ci * cj * sb));
            if (22.0 > y and y > 0.0 and x > 0.0 and 80.0 > x and m > z[o]) {
                z[o] = m;
                const nidx: usize = if (n <= 0.0) 0 else @intFromFloat(n);
                b2[o] = s[nidx];
            }
        };
        try out.writeAll("\x1b[H");
        for (0..1760) |k| if (k % 80 != 0) try out.print("{c}", .{b2[k]}) else try out.writeAll("\n");
        try out.context.flush();
        a += 0.04;
        b += 0.02;
    }
}

Works for zig 0.14.1, in master/0.15.0 writers in std will change APIs.
Zig might also make it a bit more difficult to shape your code into donut.

Robert :blush:

EDIT: As a side note, it will break your donut experience, at least for me either console or monitor refresh rate didnt keep up at all (especially in ReleaseFast) :joy:.