Ensure the pointer always ends up on an executable instruction for tui consistency
This commit is contained in:
parent
b373cbffa1
commit
2517e44899
2 changed files with 48 additions and 30 deletions
|
@ -393,35 +393,49 @@ pub const Field = struct {
|
|||
try std.testing.expectEqual(f.get(8, 2), '2');
|
||||
try std.testing.expectEqual(f.get(9, 2), ' ');
|
||||
}
|
||||
pub fn step(f: *Field, x: i64, y: i64, dx: i64, dy: i64) struct { x: i64, y: i64 } {
|
||||
pub fn step(f: *Field, x: i64, y: i64, dx: i64, dy: i64, smartAdvance: bool, jumping: bool) struct { x: i64, y: i64 } {
|
||||
var a = x + dx;
|
||||
var b = y + dy;
|
||||
if (f.isIn(a, b)) return .{ .x = a, .y = b };
|
||||
// # We are stepping outside, we need to wrap the Lahey-space
|
||||
a = x;
|
||||
b = y;
|
||||
while (true) {
|
||||
var c = a - dx;
|
||||
var d = b - dy;
|
||||
if (!f.isIn(c, d)) return .{ .x = a, .y = b };
|
||||
a = c;
|
||||
b = d;
|
||||
if (!f.isIn(a, b)) {
|
||||
// # We are stepping outside, we need to wrap the Lahey-space
|
||||
a = x;
|
||||
b = y;
|
||||
while (true) {
|
||||
var c = a - dx;
|
||||
var d = b - dy;
|
||||
if (!f.isIn(c, d)) break;
|
||||
a = c;
|
||||
b = d;
|
||||
}
|
||||
}
|
||||
if (smartAdvance) {
|
||||
const v = f.get(a, b);
|
||||
if (jumping) {
|
||||
return f.step(a, b, dx, dy, true, v != ';');
|
||||
}
|
||||
if (v == ' ') {
|
||||
return f.step(a, b, dx, dy, true, false);
|
||||
}
|
||||
if (v == ';') {
|
||||
return f.step(a, b, dx, dy, true, true);
|
||||
}
|
||||
}
|
||||
return .{ .x = a, .y = b };
|
||||
}
|
||||
test "step" {
|
||||
var minimal = std.io.fixedBufferStream("@");
|
||||
var f = try Field.init(std.testing.allocator);
|
||||
defer f.deinit();
|
||||
try f.load(minimal.reader());
|
||||
try std.testing.expectEqual(f.step(0, 0, 0, 0), .{ .x = 0, .y = 0 });
|
||||
try std.testing.expectEqual(f.step(0, 0, 1, 0), .{ .x = 0, .y = 0 });
|
||||
try std.testing.expectEqual(f.step(0, 0, 0, 0, false, false), .{ .x = 0, .y = 0 });
|
||||
try std.testing.expectEqual(f.step(0, 0, 1, 0, false, false), .{ .x = 0, .y = 0 });
|
||||
var hello = std.io.fixedBufferStream("64+\"!dlroW ,olleH\">:#,_@\n");
|
||||
var fHello = try Field.init(std.testing.allocator);
|
||||
defer fHello.deinit();
|
||||
try fHello.load(hello.reader());
|
||||
try std.testing.expectEqual(fHello.step(3, 0, 0, 0), .{ .x = 3, .y = 0 });
|
||||
try std.testing.expectEqual(fHello.step(3, 0, 1, 0), .{ .x = 4, .y = 0 });
|
||||
try std.testing.expectEqual(fHello.step(0, 0, -1, 0), .{ .x = 23, .y = 0 });
|
||||
try std.testing.expectEqual(fHello.step(3, 0, 0, 0, false, false), .{ .x = 3, .y = 0 });
|
||||
try std.testing.expectEqual(fHello.step(3, 0, 1, 0, false, false), .{ .x = 4, .y = 0 });
|
||||
try std.testing.expectEqual(fHello.step(0, 0, -1, 0, false, false), .{ .x = 23, .y = 0 });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -40,18 +40,20 @@ pub const Pointer = struct {
|
|||
switch (c) {
|
||||
'@' => return pointerReturn{},
|
||||
'z' => {},
|
||||
'#' => p.step(),
|
||||
'#' => {
|
||||
p.step(false);
|
||||
},
|
||||
'j' => {
|
||||
var n = p.ss.toss.pop();
|
||||
var j: usize = 0;
|
||||
if (n > 0) {
|
||||
while (j < n) : (j += 1) {
|
||||
p.step();
|
||||
p.step(false);
|
||||
}
|
||||
} else {
|
||||
p.reverse();
|
||||
while (j < -n) : (j += 1) {
|
||||
p.step();
|
||||
p.step(false);
|
||||
}
|
||||
p.reverse();
|
||||
}
|
||||
|
@ -61,9 +63,9 @@ pub const Pointer = struct {
|
|||
const x = p.x;
|
||||
const y = p.y;
|
||||
const n = p.ss.toss.pop();
|
||||
var v = p.stepAndGet();
|
||||
var v = p.stepAndGet(false);
|
||||
var jumpingMode = false;
|
||||
while (jumpingMode or v == ' ' or v == ';') : (v = p.stepAndGet()) {
|
||||
while (jumpingMode or v == ' ' or v == ';') : (v = p.stepAndGet(false)) {
|
||||
if (v == ';') jumpingMode = !jumpingMode;
|
||||
}
|
||||
if (n > 0) {
|
||||
|
@ -147,9 +149,11 @@ pub const Pointer = struct {
|
|||
}
|
||||
},
|
||||
'"' => p.stringMode = true,
|
||||
'\'' => try p.ss.toss.push(p.stepAndGet()),
|
||||
'\'' => {
|
||||
try p.ss.toss.push(p.stepAndGet(false));
|
||||
},
|
||||
's' => {
|
||||
p.step();
|
||||
p.step(false);
|
||||
try p.field.set(p.x, p.y, p.ss.toss.pop());
|
||||
},
|
||||
'$' => _ = p.ss.toss.pop(),
|
||||
|
@ -331,7 +335,7 @@ pub const Pointer = struct {
|
|||
if (self.stringMode) {
|
||||
if (self.lastCharWasSpace) {
|
||||
while (c == ' ') {
|
||||
c = self.stepAndGet();
|
||||
c = self.stepAndGet(false);
|
||||
}
|
||||
self.lastCharWasSpace = false;
|
||||
}
|
||||
|
@ -345,11 +349,11 @@ pub const Pointer = struct {
|
|||
var jumpingMode = false;
|
||||
while (jumpingMode or c == ' ' or c == ';') {
|
||||
if (c == ';') jumpingMode = !jumpingMode;
|
||||
c = self.stepAndGet();
|
||||
c = self.stepAndGet(false);
|
||||
}
|
||||
result = try self.eval(ioContext, c);
|
||||
}
|
||||
self.step();
|
||||
self.step(!self.stringMode);
|
||||
return result;
|
||||
}
|
||||
pub fn init(allocator: std.mem.Allocator, f: *field.Field, timestamp: ?i64, argv: []const []const u8, env: []const [*:0]const u8) !*Pointer {
|
||||
|
@ -423,13 +427,13 @@ pub const Pointer = struct {
|
|||
p.dx = -p.dx;
|
||||
p.dy = -p.dy;
|
||||
}
|
||||
inline fn step(self: *Pointer) void {
|
||||
const v = self.field.step(self.x, self.y, self.dx, self.dy);
|
||||
inline fn step(self: *Pointer, smartAdvance: bool) void {
|
||||
const v = self.field.step(self.x, self.y, self.dx, self.dy, smartAdvance, false);
|
||||
self.x = v.x;
|
||||
self.y = v.y;
|
||||
}
|
||||
inline fn stepAndGet(self: *Pointer) i64 {
|
||||
self.step();
|
||||
inline fn stepAndGet(self: *Pointer, smartAdvance: bool) i64 {
|
||||
self.step(smartAdvance);
|
||||
return self.field.get(self.x, self.y);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue