W22NXX6SH6ZSON4SCYOOOPKW5WX3572DJDQ62QHF54MZXO27KTVAC
const io = @import("io.zig");
const cursor = @import("cursor.zig");
pub const init = io.init;
var map = @import("map.zig"){};
var fruit: @import("fruit.zig") = undefined;
var head = cursor.init(0o40);
var tail = cursor.init(0o40);
pub fn main() void {
fruit.seed(io.seed());
newfruit().?;
while (true) {
io.print(head.pos, "<^>V"[head.dir]);
io.sleep();
const newdir = io.scandir(head.dir);
io.print(head.pos, " lqml kxqk jmxj"[4 * @as(u4, newdir) + head.dir]);
//push
map.store(head, newdir);
head.dir = newdir ^ 2;
head.move() orelse break;
if (head.pos != fruit.pos) {
//pop
map.load(&tail);
map.zero(tail);
//collision
if (head.mask() & map.blank() == 0)
break;
//if (tail.index() != index(head))
io.print(tail.pos, ' ');
tail.move() orelse unreachable;
} else newfruit() orelse break;
}
}
fn newfruit() ?void {
fruit.newfruit(map.blank() ^ cursor.mask(head)) orelse return null;
io.print(fruit.pos, '*');
}
const Self = @This();
const Cur = @import("cursor.zig").Self;
pub fn blank(self: Self) u64 {
return ~@reduce(.Or, self._);
}
pub fn zero(self: *Self, c: Cur) void {
self._ &= @splat(2, ~c.mask());
}
pub fn store(self: *Self, c: Cur, dir: u2) void {
const _m = @bitCast(@Vector(2, u1), dir ^ c.dir);
self._ |= @as(@Vector(2, u64), _m) << @splat(2, c.pos);
}
pub fn load(self: Self, c: *Cur) void {
const x = (self._ >> @splat(2, c.pos) & @splat(2, @as(u64, 1))) << .{ 0, 1 };
c.dir ^= 2 ^ @intCast(u2, @reduce(.Or, x));
}
//change blank to 2
_: @Vector(2, u64) = .{ 0, 0 },
const std = @import("std");
const os = std.os.linux;
const handle = std.io.getStdIn().handle;
const snake = @import("snake.zig");
pub fn main() void {
//hide cursor, clear screen, change chaeset, move cursor
const init = "\x1B[?25l\x1B[2J\x1B(0\x1B[1;1H" ++ snake.init;
_ = os.write(1, init, init.len);
//move cursor, show cursor, change charset
const deinit = "\x1B[11;1H\x1B[?25h\x1B(B";
defer _ = os.write(1, deinit, deinit.len);
const original_termios = rawmode();
defer _ = os.tcsetattr(handle, .FLUSH, &original_termios);
snake.main();
}
pub fn rawmode() os.termios {
var termios: os.termios = undefined;
_ = os.tcgetattr(handle, &termios);
var original_termios = termios;
// man 3 termios
termios.iflag &= ~@as(os.tcflag_t, os.IGNBRK | os.BRKINT | os.PARMRK | os.ISTRIP | os.INLCR | os.IGNCR | os.ICRNL | os.IXON);
termios.lflag &= ~@as(os.tcflag_t, os.ECHO | os.ECHONL | os.ICANON | os.ISIG | os.IEXTEN);
termios.oflag &= ~@as(os.tcflag_t, os.OPOST);
termios.cflag &= ~@as(os.tcflag_t, os.CSIZE | os.PARENB);
termios.cflag |= os.CS8;
termios.cc[6] = 0; // VMIN
termios.cc[5] = 0; // VTIME
_ = os.tcsetattr(handle, .FLUSH, &termios);
return original_termios;
}
test {
std.testing.refAllDecls(@This());
}
const os = @import("std").os.linux;
pub const init = ("l" ++ "q" ** 8 ++ "k\n") ++ ("x\t x\n") ** 8 ++ ("m" ++ "q" ** 8 ++ "j");
pub fn seed() u64 {
var ret: u64 = undefined;
const fd = @intCast(i32, os.open("/dev/urandom", os.O.RDONLY, undefined));
_ = os.read(fd, @ptrCast([*]u8, &ret), 8);
_ = os.close(fd);
return ret;
}
pub fn scandir(curdir: u2) u2 {
while (true) {
var buff: [1]u8 = undefined;
if (os.read(0, &buff, 1) == 0)
return curdir ^ 2;
var newdir: u2 = switch (buff[0]) {
'D' => 2, // 'D', 'H', 'h', 'a' => 2,
'C' => 0, // 'C', 'L', 'l', 'd' => 0,
'B' => 1, // 'B', 'J', 'j', 's' => 1,
'A' => 3, // 'A', 'K', 'k', 'w' => 3,
else => continue,
};
if (newdir != curdir)
return newdir;
}
}
pub var printer = "\x1B[0;0H.".*;
pub fn print(pos: u6, char: u8) void {
printer["\x1B[".len] = @as(u8, '2') + (pos >> 3);
printer["\x1B[0;".len] = @as(u8, '2') + (pos & 7);
printer[printer.len - 1] = char;
_ = os.write(1, &printer, printer.len);
}
const wait = os.timespec{ .tv_sec = 0, .tv_nsec = 1_5000_0000 };
pub fn sleep() void {
_ = os.nanosleep(&wait, null);
}
const printtype = enum {
tail,
neck,
head,
fruit,
};
// https://github.com/ziglang/zig/issues/2291
// https://github.com/ziglang/zig/issues/1717
extern fn @"llvm.x86.bmi.pdep.64"(u64, u64) u64;
const Self = @This();
const Rand = @import("std").rand.Sfc64;
pos: u6,
rand: Rand,
pub fn seed(self: *Self, s: u64) void {
self.rand = Rand.init(s);
}
pub fn newfruit(self: *Self, bb: u64) ?void {
if (bb == 0) return null;
const r = self.rand.random()
.uintLessThanBiased(u6, @intCast(u6, @popCount(bb)));
self.pos = @intCast(u6, @ctz(@"llvm.x86.bmi.pdep.64"(@as(u64, 1) << r, bb)));
}
pub usingnamespace packed struct(u8) {
pos: u6 = 0o40,
dir: u2 = 2,
pub const Self = @This();
fn to(self: Self) u8 {
return @bitCast(u8, self);
}
pub fn move(self: *Self) ?void {
const r = self.*;
@ptrCast(*i8, self).* += switch (self.dir) {
0 => -1,
1 => -8,
2 => 1,
3 => 8,
};
if (@popCount(r.to() ^ self.to()) > 3) return null;
}
pub fn mask(self: Self) u64 {
return @as(u64, 1) << self.pos;
}
pub fn init(c: u6) Self {
return .{ .pos = c };
}
};