Add coordinate type, formatting functions
parent
2df39b45f3
commit
c086c6d9de
|
@ -141,6 +141,48 @@ pub const TileData = union(enum) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Shorthand
|
||||||
|
const Coord = Coordinate;
|
||||||
|
pub const Coordinate = struct {
|
||||||
|
const LEVELSIZE = 20;
|
||||||
|
val: [2]i16,
|
||||||
|
|
||||||
|
pub fn init(val: [2]i16) Coordinate {
|
||||||
|
return Coordinate{ .val = val };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(coord: Coordinate, val: [2]i16) Coordinate {
|
||||||
|
return .{ .val = .{ coord.val[0] + val[0], coord.val[1] + val[1] } };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq(coord: Coordinate, other: Coordinate) bool {
|
||||||
|
return coord.val[0] == other.val[0] and coord.val[1] == other.val[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toWorld(coord: Coordinate) [2]i8 {
|
||||||
|
const world_x = @intCast(i8, @divFloor(coord.val[0], LEVELSIZE));
|
||||||
|
const world_y = @intCast(i8, @divFloor(coord.val[1], LEVELSIZE));
|
||||||
|
return .{ world_x, world_y };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toLevelTopLeft(coord: Coordinate) Coordinate {
|
||||||
|
const worldc = coord.toWorld();
|
||||||
|
return .{ .val = .{
|
||||||
|
@intCast(i16, worldc[0]) * LEVELSIZE,
|
||||||
|
@intCast(i16, worldc[1]) * LEVELSIZE,
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format(coord: Coordinate, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
|
_ = options;
|
||||||
|
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
|
||||||
|
return std.fmt.format(writer, "({d:>5},{d:>5})", .{ coord.val[0], coord.val[1] });
|
||||||
|
} else {
|
||||||
|
@compileError("Unknown format character: '" ++ fmt ++ "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const Level = struct {
|
pub const Level = struct {
|
||||||
world_x: i8,
|
world_x: i8,
|
||||||
world_y: i8,
|
world_y: i8,
|
||||||
|
@ -232,6 +274,16 @@ pub const Level = struct {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getTile(level: Level, globalc: Coord) ?TileData {
|
||||||
|
const tiles = level.tiles orelse return null;
|
||||||
|
const worldc = globalc.toLevelTopLeft();
|
||||||
|
const x = globalc.val[0] - worldc.val[0];
|
||||||
|
const y = globalc.val[1] - worldc.val[1];
|
||||||
|
const w = @intCast(i16, level.width);
|
||||||
|
const i = @intCast(usize, x + y * w);
|
||||||
|
return tiles[i];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getWire(level: *Level, num: usize) ?[2]Entity {
|
pub fn getWire(level: *Level, num: usize) ?[2]Entity {
|
||||||
std.debug.assert(level.entities != null);
|
std.debug.assert(level.entities != null);
|
||||||
var node_begin: ?Entity = null;
|
var node_begin: ?Entity = null;
|
||||||
|
@ -539,7 +591,17 @@ const NodeID = u16;
|
||||||
pub const CircuitNode = struct {
|
pub const CircuitNode = struct {
|
||||||
energized: bool = false,
|
energized: bool = false,
|
||||||
kind: NodeKind,
|
kind: NodeKind,
|
||||||
coord: [2]i16,
|
coord: Coordinate,
|
||||||
|
|
||||||
|
pub fn format(node: CircuitNode, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
|
_ = options;
|
||||||
|
if (fmt.len != 0) @compileError("Unknown format character: '" ++ fmt ++ "'");
|
||||||
|
return std.fmt.format(writer, "{} {c} {}", .{
|
||||||
|
node.coord,
|
||||||
|
if (node.energized) @as(u8, '1') else @as(u8, '0'),
|
||||||
|
node.kind,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const NodeKind = union(enum) {
|
pub const NodeKind = union(enum) {
|
||||||
|
@ -562,4 +624,20 @@ pub const NodeKind = union(enum) {
|
||||||
Switch: enum { Off, Bottom, Top, Left, Right },
|
Switch: enum { Off, Bottom, Top, Left, Right },
|
||||||
Join: NodeID,
|
Join: NodeID,
|
||||||
Outlet: NodeID,
|
Outlet: NodeID,
|
||||||
|
|
||||||
|
pub fn format(kind: NodeKind, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
|
_ = options;
|
||||||
|
if (fmt.len != 0) @compileError("Unknown format character: '" ++ fmt ++ "'");
|
||||||
|
const name = @tagName(kind);
|
||||||
|
return switch (kind) {
|
||||||
|
.Conduit => |Conduit| std.fmt.format(writer, "{s} [{}, {}]", .{ name, Conduit[0], Conduit[1] }),
|
||||||
|
.And => |And| std.fmt.format(writer, "{s} [{}, {}]", .{ name, And[0], And[1] }),
|
||||||
|
.Xor => |Xor| std.fmt.format(writer, "{s} [{}, {}]", .{ name, Xor[0], Xor[1] }),
|
||||||
|
.Source => std.fmt.format(writer, "{s}", .{name}),
|
||||||
|
.Plug => |Plug| std.fmt.format(writer, "{s} [{?}]", .{ name, Plug }),
|
||||||
|
.Switch => |Switch| std.fmt.format(writer, "{s} [{s}]", .{ name, @tagName(Switch) }),
|
||||||
|
.Join => |Join| std.fmt.format(writer, "{s} [{}]", .{ name, Join }),
|
||||||
|
.Outlet => |Outlet| std.fmt.format(writer, "{s} [{}]", .{ name, Outlet }),
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,7 +77,7 @@ fn make(step: *std.build.Step) !void {
|
||||||
defer circuit.deinit();
|
defer circuit.deinit();
|
||||||
// TODO
|
// TODO
|
||||||
for (circuit.items) |node, i| {
|
for (circuit.items) |node, i| {
|
||||||
std.log.warn("[{:0>2}]: {s:<10} {any}\t\t{}", .{ i, @tagName(node.kind), node.coord, node.kind });
|
std.log.warn("{:0>2}: {}", .{ i, node });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the offset of each level and store it in the headers.
|
// Calculate the offset of each level and store it in the headers.
|
||||||
|
@ -279,10 +279,10 @@ fn parseLevel(opt: struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayList(world.CircuitNode) {
|
pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayList(world.CircuitNode) {
|
||||||
const Coordinate = [2]i16;
|
const Coord = world.Coordinate;
|
||||||
const SearchItem = struct {
|
const SearchItem = struct {
|
||||||
coord: Coordinate,
|
coord: Coord,
|
||||||
last_coord: ?Coordinate = null,
|
last_coord: ?Coord = null,
|
||||||
last_node: u16,
|
last_node: u16,
|
||||||
};
|
};
|
||||||
const Queue = std.TailQueue(SearchItem);
|
const Queue = std.TailQueue(SearchItem);
|
||||||
|
@ -302,15 +302,15 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
try level_hashmap.put(id, level);
|
try level_hashmap.put(id, level);
|
||||||
|
|
||||||
// Use a global coordinate system for our algorithm
|
// Use a global coordinate system for our algorithm
|
||||||
const world_x = @intCast(i16, level.world_x) * 20;
|
const global_x = @intCast(i16, level.world_x) * 20;
|
||||||
const world_y = @intCast(i16, level.world_y) * 20;
|
const global_y = @intCast(i16, level.world_y) * 20;
|
||||||
for (level.tiles orelse continue) |tileData, i| {
|
for (level.tiles orelse continue) |tileData, i| {
|
||||||
const x = world_x + @intCast(i16, @mod(i, level.width));
|
const x = global_x + @intCast(i16, @mod(i, level.width));
|
||||||
const y = world_y + @intCast(i16, @divTrunc(i, level.width));
|
const y = global_y + @intCast(i16, @divTrunc(i, level.width));
|
||||||
const coordinate = try alloc.create(Node);
|
const coordinate = try alloc.create(Node);
|
||||||
coordinate.* = .{ .data = .{
|
coordinate.* = .{ .data = .{
|
||||||
.last_node = @intCast(u16, nodes.items.len),
|
.last_node = @intCast(u16, nodes.items.len),
|
||||||
.coord = .{ x, y },
|
.coord = Coord.init(.{ x, y }),
|
||||||
} };
|
} };
|
||||||
switch (tileData) {
|
switch (tileData) {
|
||||||
.tile => |_| {
|
.tile => |_| {
|
||||||
|
@ -319,7 +319,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
.flags => |flags| {
|
.flags => |flags| {
|
||||||
switch (flags.circuit) {
|
switch (flags.circuit) {
|
||||||
.Source => {
|
.Source => {
|
||||||
try nodes.append(.{ .kind = .Source, .coord = .{ x, y } });
|
try nodes.append(.{ .kind = .Source, .coord = Coord.init(.{ x, y }) });
|
||||||
sources.append(coordinate);
|
sources.append(coordinate);
|
||||||
},
|
},
|
||||||
.Plug => {
|
.Plug => {
|
||||||
|
@ -336,9 +336,9 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var visited = std.AutoHashMap(Coordinate, void).init(alloc);
|
var visited = std.AutoHashMap(Coord, void).init(alloc);
|
||||||
defer visited.deinit();
|
defer visited.deinit();
|
||||||
var multi_input = std.AutoHashMap(Coordinate, usize).init(alloc);
|
var multi_input = std.AutoHashMap(Coord, usize).init(alloc);
|
||||||
defer multi_input.deinit();
|
defer multi_input.deinit();
|
||||||
|
|
||||||
var bfs_queue = Queue{};
|
var bfs_queue = Queue{};
|
||||||
|
@ -356,32 +356,25 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
if (visited.contains(coord)) continue;
|
if (visited.contains(coord)) continue;
|
||||||
try visited.put(coord, .{});
|
try visited.put(coord, .{});
|
||||||
// TODO remove magic numbers
|
// TODO remove magic numbers
|
||||||
const LEVELSIZE = 20;
|
const worldc = coord.toWorld();
|
||||||
const world_x = @intCast(i8, @divFloor(coord[0], LEVELSIZE));
|
const id: u16 = @bitCast(u8, worldc[0]) | @intCast(u16, @bitCast(u8, worldc[1])) << 8;
|
||||||
const world_y = @intCast(i8, @divFloor(coord[1], LEVELSIZE));
|
|
||||||
const id: u16 = @bitCast(u8, world_x) | @intCast(u16, @bitCast(u8, world_y)) << 8;
|
|
||||||
// const level_opt: ?world.Level = level_hashmap.get(.{ world_x, world_y });
|
// const level_opt: ?world.Level = level_hashmap.get(.{ world_x, world_y });
|
||||||
if (level_hashmap.getPtr(id) != null) {
|
if (level_hashmap.getPtr(id) != null) {
|
||||||
const level = level_hashmap.getPtr(id);
|
const level = level_hashmap.getPtr(id);
|
||||||
const level_x = @intCast(i16, world_x) * LEVELSIZE;
|
|
||||||
const level_y = @intCast(i16, world_y) * LEVELSIZE;
|
|
||||||
const i = @intCast(usize, (coord[0] - level_x) + (coord[1] - level_y) * @intCast(i16, level.?.width));
|
|
||||||
const last_node = node.data.last_node;
|
const last_node = node.data.last_node;
|
||||||
var next_node = last_node;
|
var next_node = last_node;
|
||||||
|
|
||||||
const tile = level.?.tiles.?[i];
|
const tile = level.?.getTile(coord).?;
|
||||||
|
|
||||||
if (tile != .flags) continue;
|
if (tile != .flags) continue;
|
||||||
const flags = tile.flags;
|
const flags = tile.flags;
|
||||||
|
|
||||||
switch (flags.circuit) {
|
switch (flags.circuit) {
|
||||||
.Conduit => {
|
.Source, .Conduit => {
|
||||||
// Collects from two other nodes. Needs to store more info in coordinate queue
|
// Collects from two other nodes. Needs to store more info in coordinate queue
|
||||||
// TODO
|
// TODO
|
||||||
},
|
},
|
||||||
.Plug,
|
.Plug => {
|
||||||
.Source,
|
|
||||||
=> {
|
|
||||||
// These have already been added, so just continue the
|
// These have already been added, so just continue the
|
||||||
// search
|
// search
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(u16, nodes.items.len);
|
||||||
|
@ -414,11 +407,17 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.Join => {
|
.Join => {
|
||||||
|
const last_coord = node.data.last_coord.?;
|
||||||
|
if (last_coord.toLevelTopLeft().eq(coord.toLevelTopLeft())) {
|
||||||
|
std.log.warn("Join first side", .{});
|
||||||
|
} else {
|
||||||
|
std.log.warn("Join second side", .{});
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(u16, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .Join = last_node },
|
.kind = .{ .Join = last_node },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.And => {
|
.And => {
|
||||||
// TODO: verify And gate is properly connected. A source node
|
// TODO: verify And gate is properly connected. A source node
|
||||||
|
@ -427,9 +426,9 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
const last_coord = node.data.last_coord.?;
|
const last_coord = node.data.last_coord.?;
|
||||||
const Side = enum { O, L, R };
|
const Side = enum { O, L, R };
|
||||||
const side: Side =
|
const side: Side =
|
||||||
if (last_coord[0] == coord[0] - 1)
|
if (last_coord.val[0] == coord.val[0] - 1)
|
||||||
Side.L
|
Side.L
|
||||||
else if (last_coord[0] == coord[0] + 1)
|
else if (last_coord.val[0] == coord.val[0] + 1)
|
||||||
Side.R
|
Side.R
|
||||||
else
|
else
|
||||||
Side.O;
|
Side.O;
|
||||||
|
@ -449,6 +448,8 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
} else {
|
} else {
|
||||||
_ = visited.remove(coord);
|
_ = visited.remove(coord);
|
||||||
if (side == .O) {
|
if (side == .O) {
|
||||||
|
// TODO: reverse the path, since the search path
|
||||||
|
// may have come from a plug
|
||||||
return error.OutputToSource;
|
return error.OutputToSource;
|
||||||
} else if (side == .L) {
|
} else if (side == .L) {
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(u16, nodes.items.len);
|
||||||
|
@ -471,9 +472,9 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
const last_coord = node.data.last_coord.?;
|
const last_coord = node.data.last_coord.?;
|
||||||
const Side = enum { O, L, R };
|
const Side = enum { O, L, R };
|
||||||
const side: Side =
|
const side: Side =
|
||||||
if (last_coord[0] == coord[0] - 1)
|
if (last_coord.val[0] == coord.val[0] - 1)
|
||||||
Side.L
|
Side.L
|
||||||
else if (last_coord[0] == coord[0] + 1)
|
else if (last_coord.val[0] == coord.val[0] + 1)
|
||||||
Side.R
|
Side.R
|
||||||
else
|
else
|
||||||
Side.O;
|
Side.O;
|
||||||
|
@ -493,6 +494,8 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
} else {
|
} else {
|
||||||
_ = visited.remove(coord);
|
_ = visited.remove(coord);
|
||||||
if (side == .O) {
|
if (side == .O) {
|
||||||
|
// TODO: reverse the path, since the search path
|
||||||
|
// may have come from a plug
|
||||||
return error.OutputToSource;
|
return error.OutputToSource;
|
||||||
} else if (side == .L) {
|
} else if (side == .L) {
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(u16, nodes.items.len);
|
||||||
|
@ -520,22 +523,22 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
|
|
||||||
right.* = Node{ .data = .{
|
right.* = Node{ .data = .{
|
||||||
.last_node = next_node,
|
.last_node = next_node,
|
||||||
.coord = .{ coord[0] + 1, coord[1] },
|
.coord = coord.add(.{ 1, 0 }),
|
||||||
.last_coord = coord,
|
.last_coord = coord,
|
||||||
} };
|
} };
|
||||||
left.* = Node{ .data = .{
|
left.* = Node{ .data = .{
|
||||||
.last_node = next_node,
|
.last_node = next_node,
|
||||||
.coord = .{ coord[0] - 1, coord[1] },
|
.coord = coord.add(.{ -1, 0 }),
|
||||||
.last_coord = coord,
|
.last_coord = coord,
|
||||||
} };
|
} };
|
||||||
down.* = Node{ .data = .{
|
down.* = Node{ .data = .{
|
||||||
.last_node = next_node,
|
.last_node = next_node,
|
||||||
.coord = .{ coord[0], coord[1] + 1 },
|
.coord = coord.add(.{ 0, 1 }),
|
||||||
.last_coord = coord,
|
.last_coord = coord,
|
||||||
} };
|
} };
|
||||||
up.* = Node{ .data = .{
|
up.* = Node{ .data = .{
|
||||||
.last_node = next_node,
|
.last_node = next_node,
|
||||||
.coord = .{ coord[0], coord[1] - 1 },
|
.coord = coord.add(.{ 0, -1 }),
|
||||||
.last_coord = coord,
|
.last_coord = coord,
|
||||||
} };
|
} };
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue