Begin adding directed conduit pieces
parent
e36cffb8c6
commit
4ccc7e9a2e
File diff suppressed because it is too large
Load Diff
|
@ -1 +1 @@
|
|||
Subproject commit 1c85773b680b25d690b95e5c88b2e5bfe9ba534a
|
||||
Subproject commit d1ace5b48eaf1caa3bce44add0d14e4fb2f10061
|
18
flake.lock
18
flake.lock
|
@ -32,11 +32,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1660017629,
|
||||
"narHash": "sha256-Koz6/k7c6hx4qVz/bboxdR2QsBdkxjRWpNmsOWJtXZE=",
|
||||
"lastModified": 1660137652,
|
||||
"narHash": "sha256-L92gcG6Ya4bqjJmStl/HTENhc0PR9lmVgTmeVpk13Os=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9f15d6c3a74d2778c6e1af67947c95f100dc6fd2",
|
||||
"rev": "a7f89ddd6313ef88fc9c6534ac2511ba9da85fdb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -70,11 +70,11 @@
|
|||
},
|
||||
"unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1659981942,
|
||||
"narHash": "sha256-uCFiP/B/NXOWzhN6TKfMbSxtVMk1bVnCrnJRjCF6RmU=",
|
||||
"lastModified": 1660071133,
|
||||
"narHash": "sha256-XX6T9wcvEZIVWY4TO5O1d2MgFyFrF2v4TpCFs7fjdn8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "39d7f929fbcb1446ad7aa7441b04fb30625a4190",
|
||||
"rev": "36cc29d837e7232e3176e4651e8e117a6f231793",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -89,11 +89,11 @@
|
|||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1659919434,
|
||||
"narHash": "sha256-U6QsM5FbFpEkqPfXwe/QvNdCWwBIXW9A3fhXo3hFps8=",
|
||||
"lastModified": 1660096418,
|
||||
"narHash": "sha256-+NewKwnerjOe5e65y0xwlRzoQ6JoKP2EaZLR+72d8wU=",
|
||||
"owner": "arqv",
|
||||
"repo": "zig-overlay",
|
||||
"rev": "db9604e7fff0a41f06302d61dd4f320c4e23b81e",
|
||||
"rev": "f7f0dd5bc40290187c70245d11b61c2305e4f114",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -46,7 +46,7 @@ pub fn extractLevel(opt: Options) !void {
|
|||
circuit.map_size = .{ level.width, height };
|
||||
|
||||
w4.tracef("%d", @src().line);
|
||||
var auto_map = try alloc.alloc(bool, size);
|
||||
var auto_map = try alloc.alloc(world.SolidType, size);
|
||||
defer alloc.free(auto_map);
|
||||
|
||||
var circuit_map = try alloc.alloc(CircuitType, size);
|
||||
|
@ -56,7 +56,7 @@ pub fn extractLevel(opt: Options) !void {
|
|||
for (tiles) |data, i| {
|
||||
switch (data) {
|
||||
.tile => |tile| {
|
||||
auto_map[i] = false;
|
||||
auto_map[i] = .Empty;
|
||||
map.tiles[i] = tile;
|
||||
circuit_map[i] = .None;
|
||||
},
|
||||
|
@ -79,7 +79,7 @@ pub fn extractLevel(opt: Options) !void {
|
|||
const y = @divTrunc(i, width);
|
||||
const stride = width;
|
||||
|
||||
if (!auto_map[i]) {
|
||||
if (auto_map[i] == .Empty) {
|
||||
autotiles[i] = null;
|
||||
continue;
|
||||
}
|
||||
|
@ -93,25 +93,25 @@ pub fn extractLevel(opt: Options) !void {
|
|||
// Check horizontal neighbors
|
||||
if (x == 0) {
|
||||
west = out_of_bounds;
|
||||
east = auto_map[i + 1];
|
||||
east = auto_map[i + 1] == .Solid;
|
||||
} else if (x == width - 1) {
|
||||
west = auto_map[i - 1];
|
||||
west = auto_map[i - 1] == .Solid;
|
||||
east = out_of_bounds;
|
||||
} else {
|
||||
west = auto_map[i - 1];
|
||||
east = auto_map[i + 1];
|
||||
west = auto_map[i - 1] == .Solid;
|
||||
east = auto_map[i + 1] == .Solid;
|
||||
}
|
||||
|
||||
// Check vertical neighbours
|
||||
if (y == 0) {
|
||||
north = out_of_bounds;
|
||||
south = auto_map[i + stride];
|
||||
south = auto_map[i + stride] == .Solid;
|
||||
} else if (y == height - 1) {
|
||||
north = auto_map[i - stride];
|
||||
north = auto_map[i - stride] == .Solid;
|
||||
south = out_of_bounds;
|
||||
} else {
|
||||
north = auto_map[i - stride];
|
||||
south = auto_map[i + stride];
|
||||
north = auto_map[i - stride] == .Solid;
|
||||
south = auto_map[i + stride] == .Solid;
|
||||
}
|
||||
|
||||
autotiles[i] = AutoTile{
|
||||
|
@ -203,12 +203,18 @@ pub fn extractLevel(opt: Options) !void {
|
|||
for (autotiles) |autotile_opt, i| {
|
||||
if (autotile_opt) |autotile| {
|
||||
const tile = switch (circuit_map[i]) {
|
||||
.Conduit, .Source, .Join => opt.conduit.find(autotile),
|
||||
.Conduit,
|
||||
.Conduit_Vertical,
|
||||
.Conduit_Horizontal,
|
||||
.Source,
|
||||
.Join,
|
||||
=> opt.conduit.find(autotile),
|
||||
.Switch_On => opt.switch_on.find(autotile),
|
||||
.Switch_Off => opt.switch_off.find(autotile),
|
||||
.Plug, .Socket => opt.plug.find(autotile),
|
||||
.And => world.Tiles.LogicAnd,
|
||||
.Xor => world.Tiles.LogicXor,
|
||||
.Diode => world.Tiles.LogicDiode,
|
||||
.None, .Outlet => 0,
|
||||
};
|
||||
circuit.map[i] = tile;
|
||||
|
|
|
@ -2,22 +2,6 @@
|
|||
|
||||
const std = @import("std");
|
||||
|
||||
/// The CircuitType of a tile modifies how the tile responds to
|
||||
/// electricity
|
||||
pub const CircuitType = enum(u4) {
|
||||
None = 0,
|
||||
Conduit = 1,
|
||||
Plug = 2,
|
||||
Switch_Off = 3,
|
||||
Switch_On = 4,
|
||||
Join = 5,
|
||||
And = 6,
|
||||
Xor = 7,
|
||||
Outlet = 8,
|
||||
Source = 9,
|
||||
Socket = 10,
|
||||
};
|
||||
|
||||
/// This lists the most important tiles so I don't have to keep rewriting things
|
||||
pub const Tiles = struct {
|
||||
// Switches
|
||||
|
@ -50,9 +34,10 @@ pub const Tiles = struct {
|
|||
pub const LogicAnd = 20;
|
||||
pub const LogicNot = 21;
|
||||
pub const LogicXor = 22;
|
||||
pub const LogicDiode = 23;
|
||||
|
||||
pub fn is_logic(tile: u8) bool {
|
||||
return tile >= 21 and tile <= 24;
|
||||
return tile >= LogicAnd and tile <= LogicDiode;
|
||||
}
|
||||
|
||||
pub const ConduitCross = 96;
|
||||
|
@ -109,29 +94,52 @@ pub const Tiles = struct {
|
|||
}, 2);
|
||||
};
|
||||
|
||||
pub const SolidType = enum(u2) {
|
||||
Empty = 0,
|
||||
Solid = 1,
|
||||
Oneway = 2,
|
||||
};
|
||||
|
||||
/// The CircuitType of a tile modifies how the tile responds to
|
||||
/// electricity
|
||||
pub const CircuitType = enum(u5) {
|
||||
None = 0,
|
||||
Conduit = 1,
|
||||
Plug = 2,
|
||||
Switch_Off = 3,
|
||||
Switch_On = 4,
|
||||
Join = 5,
|
||||
And = 6,
|
||||
Xor = 7,
|
||||
Outlet = 8,
|
||||
Source = 9,
|
||||
Socket = 10,
|
||||
Diode = 11,
|
||||
Conduit_Vertical = 12,
|
||||
Conduit_Horizontal = 13,
|
||||
};
|
||||
|
||||
pub const TileData = union(enum) {
|
||||
tile: u7,
|
||||
flags: struct {
|
||||
solid: bool,
|
||||
solid: SolidType,
|
||||
circuit: CircuitType,
|
||||
},
|
||||
|
||||
pub fn getCircuit(data: TileData) ?CircuitType {
|
||||
switch (data) {
|
||||
.tile => |_| return null,
|
||||
.flags => |flags| {
|
||||
if (flags.circuit == .None) return null;
|
||||
return flags.circuit;
|
||||
},
|
||||
if (data == .flags) {
|
||||
return data.flags.circuit;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn toByte(data: TileData) u8 {
|
||||
switch (data) {
|
||||
.tile => |int| return 0b1000_0000 | @intCast(u8, int),
|
||||
.flags => |flags| {
|
||||
const solid = @enumToInt(flags.solid);
|
||||
const circuit = @enumToInt(flags.circuit);
|
||||
return (@intCast(u7, @boolToInt(flags.solid))) | (@intCast(u7, circuit) << 1);
|
||||
return 0b0111_1111 & ((@intCast(u7, solid)) | (@intCast(u7, circuit) << 2));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -139,13 +147,13 @@ pub const TileData = union(enum) {
|
|||
pub fn fromByte(byte: u8) TileData {
|
||||
const is_tile = (0b1000_0000 & byte) > 0;
|
||||
if (is_tile) {
|
||||
const tile = @intCast(u7, (0b0111_1111 & byte));
|
||||
const tile = @intCast(u7, (0b0000_0011 & byte));
|
||||
return TileData{ .tile = tile };
|
||||
} else {
|
||||
const is_solid = (0b0000_0001 & byte) > 0;
|
||||
const circuit = @intCast(u4, (0b0001_1110 & byte) >> 1);
|
||||
const solid = (0b0000_0011 & byte);
|
||||
const circuit = @intCast(u5, (0b0111_1100 & byte) >> 2);
|
||||
return TileData{ .flags = .{
|
||||
.solid = is_solid,
|
||||
.solid = @intToEnum(SolidType, solid),
|
||||
.circuit = @intToEnum(CircuitType, circuit),
|
||||
} };
|
||||
}
|
||||
|
@ -257,12 +265,12 @@ pub const Level = struct {
|
|||
size: u16,
|
||||
tiles: ?[]TileData,
|
||||
|
||||
pub fn init(x: u8, y: u8, width: u16, buf: []TileData) Level {
|
||||
pub fn init(x: i8, y: i8, width: u16, buf: []TileData) Level {
|
||||
return Level{
|
||||
.world_x = x,
|
||||
.world_y = y,
|
||||
.width = width,
|
||||
.size = buf.len,
|
||||
.size = @intCast(u16, buf.len),
|
||||
.tiles = buf,
|
||||
};
|
||||
}
|
||||
|
@ -310,9 +318,11 @@ pub const Level = struct {
|
|||
pub fn getTile(level: Level, globalc: Coord) ?TileData {
|
||||
const tiles = level.tiles orelse return null;
|
||||
const worldc = globalc.toLevelTopLeft();
|
||||
const se = worldc.add(.{ 20, 20 });
|
||||
if (!globalc.within(worldc, se)) return null;
|
||||
const x = globalc.val[0] - worldc.val[0];
|
||||
const y = globalc.val[1] - worldc.val[1];
|
||||
const w = @intCast(i16, level.width);
|
||||
const w = @intCast(i32, level.width);
|
||||
const i = @intCast(usize, x + y * w);
|
||||
return tiles[i];
|
||||
}
|
||||
|
@ -817,25 +827,30 @@ pub const Database = struct {
|
|||
if (visited[i]) return db.circuit_info[i].energized;
|
||||
visited[i] = true;
|
||||
const node = db.circuit_info[i];
|
||||
const w4 = @import("wasm4.zig");
|
||||
switch (node.kind) {
|
||||
.And => |And| {
|
||||
w4.tracef("[updateCircuitFragment] %d And %d %d", i, And[0], And[1]);
|
||||
const input1 = db.updateCircuitFragment(And[0], visited);
|
||||
const input2 = db.updateCircuitFragment(And[1], visited);
|
||||
db.circuit_info[i].energized = (input1 and input2);
|
||||
},
|
||||
.Xor => |Xor| {
|
||||
w4.tracef("[updateCircuitFragment] %d Xor", i);
|
||||
const input1 = db.updateCircuitFragment(Xor[0], visited);
|
||||
const input2 = db.updateCircuitFragment(Xor[1], visited);
|
||||
db.circuit_info[i].energized = (input1 and !input2) or (input2 and !input1);
|
||||
},
|
||||
.Source => db.circuit_info[i].energized = true,
|
||||
.Conduit => |Conduit| {
|
||||
w4.tracef("[updateCircuitFragment] %d Conduit", i);
|
||||
const input1 = db.updateCircuitFragment(Conduit[0], visited);
|
||||
const input2 = db.updateCircuitFragment(Conduit[1], visited);
|
||||
db.circuit_info[i].energized = (input1 or input2);
|
||||
},
|
||||
// TODO: Sockets may come before the plug they are connected to
|
||||
.Socket => |socket_opt| {
|
||||
w4.tracef("[updateCircuitFragment] %d Socket", i);
|
||||
if (socket_opt) |input| {
|
||||
db.circuit_info[i].energized = db.updateCircuitFragment(input, visited);
|
||||
} else {
|
||||
|
@ -843,12 +858,15 @@ pub const Database = struct {
|
|||
}
|
||||
},
|
||||
.Plug => |Plug| {
|
||||
w4.tracef("[updateCircuitFragment] %d Plug", i);
|
||||
db.circuit_info[i].energized = db.updateCircuitFragment(Plug, visited);
|
||||
},
|
||||
.Switch => |_Switch| {
|
||||
w4.tracef("[updateCircuitFragment] %d Switch %d", i, _Switch.source);
|
||||
db.circuit_info[i].energized = db.updateCircuitFragment(_Switch.source, visited);
|
||||
},
|
||||
.SwitchOutlet => |_Switch| {
|
||||
w4.tracef("[updateCircuitFragment] %d Switch Outlet", i);
|
||||
const is_energized = db.updateCircuitFragment(_Switch.source, visited);
|
||||
const _switch = db.circuit_info[_Switch.source].kind.Switch;
|
||||
const _outlet = db.circuit_info[i].kind.SwitchOutlet;
|
||||
|
@ -858,12 +876,15 @@ pub const Database = struct {
|
|||
db.circuit_info[i].energized = _outlet.which == _switch.state;
|
||||
},
|
||||
.Join => |Join| {
|
||||
w4.tracef("[updateCircuitFragment] %d Join", i);
|
||||
db.circuit_info[i].energized = db.updateCircuitFragment(Join, visited);
|
||||
},
|
||||
.Outlet => |Outlet| {
|
||||
w4.tracef("[updateCircuitFragment] %d Outlet", i);
|
||||
db.circuit_info[i].energized = db.updateCircuitFragment(Outlet, visited);
|
||||
},
|
||||
}
|
||||
w4.tracef("[updateCircuitFragment] %d end", i);
|
||||
return db.circuit_info[i].energized;
|
||||
}
|
||||
|
||||
|
@ -872,6 +893,8 @@ pub const Database = struct {
|
|||
defer alloc.free(visited);
|
||||
std.mem.set(bool, visited, false);
|
||||
var i: usize = db.circuit_info.len - 1;
|
||||
const w4 = @import("wasm4.zig");
|
||||
w4.tracef("[updateCircuit] circuit info len %d", db.circuit_info.len);
|
||||
while (i > 0) : (i -|= 1) {
|
||||
_ = db.updateCircuitFragment(i, visited);
|
||||
if (i == 0) break;
|
||||
|
|
|
@ -152,8 +152,8 @@ fn parseLevel(opt: struct {
|
|||
|
||||
const layers = level.layerInstances orelse return error.NoLayers;
|
||||
|
||||
const world_x: i8 = @intCast(i8, @divExact(level.worldX, (ldtk.worldGridWidth orelse 160)));
|
||||
const world_y: i8 = @intCast(i8, @divExact(level.worldY, (ldtk.worldGridHeight orelse 160)));
|
||||
const world_x: i8 = @intCast(i8, @divFloor(level.worldX, (ldtk.worldGridWidth orelse 160)));
|
||||
const world_y: i8 = @intCast(i8, @divFloor(level.worldY, (ldtk.worldGridHeight orelse 160)));
|
||||
|
||||
var circuit_layer: ?LDtk.LayerInstance = null;
|
||||
var collision_layer: ?LDtk.LayerInstance = null;
|
||||
|
@ -285,15 +285,23 @@ fn parseLevel(opt: struct {
|
|||
|
||||
// Add circuit tiles
|
||||
for (circuit.intGridCsv) |cir64, i| {
|
||||
const cir = @intCast(u4, cir64);
|
||||
const cir = @intToEnum(world.CircuitType, @intCast(u5, cir64));
|
||||
const col = collision.intGridCsv[i];
|
||||
if (col == 0 or col == 1) {
|
||||
if (cir != .None and col == 2) return error.DebrisAndCircuitOverlapped;
|
||||
if (cir == .None) continue;
|
||||
const solid: world.SolidType = switch (col) {
|
||||
0 => .Empty,
|
||||
1 => .Solid,
|
||||
3 => .Oneway,
|
||||
else => return error.DebrisAndCircuitOverlapped,
|
||||
};
|
||||
if (cir == .Socket)
|
||||
std.log.warn("[parseLevel] {}: {}", .{ i, cir });
|
||||
tiles[i] = world.TileData{ .flags = .{
|
||||
.solid = col == 1,
|
||||
.circuit = @intToEnum(world.CircuitType, cir),
|
||||
.solid = solid,
|
||||
.circuit = cir,
|
||||
} };
|
||||
}
|
||||
}
|
||||
|
||||
return parsed_level;
|
||||
}
|
||||
|
@ -313,22 +321,15 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
var sources = Queue{};
|
||||
var sockets = Queue{};
|
||||
|
||||
var level_hashmap = std.AutoHashMap(u16, world.Level).init(alloc);
|
||||
defer level_hashmap.deinit();
|
||||
|
||||
for (levels) |level| {
|
||||
const id: u16 = @bitCast(u8, level.world_x) | @intCast(u16, @bitCast(u8, level.world_y)) << 8;
|
||||
// So we can quickly find levels
|
||||
try level_hashmap.put(id, level);
|
||||
|
||||
// Use a global coordinate system for our algorithm
|
||||
const global_x = @intCast(i16, level.world_x) * 20;
|
||||
const global_y = @intCast(i16, level.world_y) * 20;
|
||||
for (level.tiles orelse continue) |tileData, i| {
|
||||
const x = global_x + @intCast(i16, @mod(i, level.width));
|
||||
const y = global_y + @intCast(i16, @divTrunc(i, level.width));
|
||||
const coordinate = try alloc.create(Node);
|
||||
coordinate.* = .{ .data = .{
|
||||
const search_item = try alloc.create(Node);
|
||||
search_item.* = .{ .data = .{
|
||||
.last_node = @intCast(world.NodeID, nodes.items.len),
|
||||
.coord = Coord.init(.{ x, y }),
|
||||
} };
|
||||
|
@ -340,12 +341,11 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
switch (flags.circuit) {
|
||||
.Source => {
|
||||
try nodes.append(.{ .kind = .Source, .coord = Coord.init(.{ x, y }) });
|
||||
sources.append(coordinate);
|
||||
sources.append(search_item);
|
||||
},
|
||||
.Socket => {
|
||||
// try nodes.append(.{ .kind = .{ .Plug = null } });
|
||||
coordinate.data.last_node = std.math.maxInt(world.NodeID);
|
||||
sockets.append(coordinate);
|
||||
search_item.data.last_node = std.math.maxInt(world.NodeID);
|
||||
sockets.append(search_item);
|
||||
},
|
||||
else => {
|
||||
// Do nothing
|
||||
|
@ -367,24 +367,22 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
while (run < 2) : (run += 1) {
|
||||
if (run == 0) bfs_queue.concatByMoving(&sources);
|
||||
if (run == 1) bfs_queue.concatByMoving(&sockets);
|
||||
// bfs_queue.concatByMoving(&outlets);
|
||||
|
||||
while (bfs_queue.popFirst()) |node| {
|
||||
// Make sure we clean up the node's memory
|
||||
defer alloc.destroy(node);
|
||||
const coord = node.data.coord;
|
||||
if (visited.contains(coord)) continue;
|
||||
try visited.put(coord, .{});
|
||||
// TODO remove magic numbers
|
||||
try visited.put(coord, {});
|
||||
|
||||
const worldc = coord.toWorld();
|
||||
const id: u16 = @bitCast(u8, worldc[0]) | @intCast(u16, @bitCast(u8, worldc[1])) << 8;
|
||||
// const level_opt: ?world.Level = level_hashmap.get(.{ world_x, world_y });
|
||||
if (level_hashmap.getPtr(id) != null) {
|
||||
const level = level_hashmap.getPtr(id);
|
||||
// const level = getLevel(levels, worldc[0], worldc[1]);
|
||||
if (getLevel(levels, worldc[0], worldc[1])) |level| {
|
||||
const last_node = node.data.last_node;
|
||||
var next_node = last_node;
|
||||
|
||||
const tile = level.?.getTile(coord).?;
|
||||
const tile = level.getTile(coord) orelse continue;
|
||||
std.log.warn("[buildCircuit] {} [{}] {}", .{ coord, node.data.last_node, tile });
|
||||
|
||||
if (tile != .flags) continue;
|
||||
const flags = tile.flags;
|
||||
|
@ -397,6 +395,56 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
// previous nodes to point to the conduit
|
||||
// TODO
|
||||
},
|
||||
.Conduit_Horizontal => {
|
||||
// Skip vertical inputs
|
||||
const last_coord = node.data.last_coord.?;
|
||||
const input_dir: Dir = getInputDirection(coord, last_coord);
|
||||
if (input_dir == .North or input_dir == .South) {
|
||||
_ = visited.remove(coord);
|
||||
continue;
|
||||
}
|
||||
const left = try alloc.create(Node);
|
||||
left.* = Node{ .data = .{
|
||||
.last_node = last_node,
|
||||
.coord = coord.add(.{ -1, 0 }),
|
||||
.last_coord = coord,
|
||||
} };
|
||||
bfs_queue.append(left);
|
||||
|
||||
const right = try alloc.create(Node);
|
||||
right.* = Node{ .data = .{
|
||||
.last_node = last_node,
|
||||
.coord = coord.add(.{ 1, 0 }),
|
||||
.last_coord = coord,
|
||||
} };
|
||||
bfs_queue.append(right);
|
||||
continue;
|
||||
},
|
||||
.Conduit_Vertical => {
|
||||
// Skip horizontal inputs
|
||||
const last_coord = node.data.last_coord.?;
|
||||
const input_dir: Dir = getInputDirection(coord, last_coord);
|
||||
if (input_dir == .West or input_dir == .East) {
|
||||
_ = visited.remove(coord);
|
||||
continue;
|
||||
}
|
||||
const up = try alloc.create(Node);
|
||||
up.* = Node{ .data = .{
|
||||
.last_node = last_node,
|
||||
.coord = coord.add(.{ 0, -1 }),
|
||||
.last_coord = coord,
|
||||
} };
|
||||
bfs_queue.append(up);
|
||||
|
||||
const down = try alloc.create(Node);
|
||||
down.* = Node{ .data = .{
|
||||
.last_node = last_node,
|
||||
.coord = coord.add(.{ 0, 1 }),
|
||||
.last_coord = coord,
|
||||
} };
|
||||
bfs_queue.append(down);
|
||||
continue;
|
||||
},
|
||||
.Socket => {
|
||||
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||
try nodes.append(.{
|
||||
|
@ -423,28 +471,39 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
.Switch_Off, .Switch_On => {
|
||||
// Identify input side
|
||||
const last_coord = node.data.last_coord.?;
|
||||
const Dir = enum { North, West, East, South };
|
||||
const input_dir: Dir = dir: {
|
||||
if (last_coord.eq(coord.add(.{ 0, -1 }))) {
|
||||
break :dir .North;
|
||||
} else if (last_coord.eq(coord.add(.{ -1, 0 }))) {
|
||||
break :dir .West;
|
||||
} else if (last_coord.eq(coord.add(.{ 1, 0 }))) {
|
||||
break :dir .East;
|
||||
} else {
|
||||
break :dir .South;
|
||||
}
|
||||
};
|
||||
const input_dir: Dir = getInputDirection(coord, last_coord);
|
||||
// Find outlets
|
||||
const north_opt = level.?.getTile(coord.add(.{ 0, -1 })).?.getCircuit();
|
||||
const west_opt = level.?.getTile(coord.add(.{ -1, 0 })).?.getCircuit();
|
||||
const east_opt = level.?.getTile(coord.add(.{ 1, 0 })).?.getCircuit();
|
||||
const south_opt = level.?.getTile(coord.add(.{ 0, 1 })).?.getCircuit();
|
||||
const ncoord = coord.add(.{ 0, -1 });
|
||||
const wcoord = coord.add(.{ -1, 0 });
|
||||
const ecoord = coord.add(.{ 1, 0 });
|
||||
const scoord = coord.add(.{ 0, 1 });
|
||||
|
||||
const north = (north_opt orelse world.CircuitType.None) != .None;
|
||||
const west = (west_opt orelse world.CircuitType.None) != .None;
|
||||
const east = (east_opt orelse world.CircuitType.None) != .None;
|
||||
const south = (south_opt orelse world.CircuitType.None) != .None;
|
||||
const north_opt = if (level.getTile(ncoord)) |t| t.getCircuit() else @panic("AAAAA");
|
||||
const west_opt = if (level.getTile(wcoord)) |t| t.getCircuit() else @panic("AAAAA");
|
||||
const east_opt = if (level.getTile(ecoord)) |t| t.getCircuit() else @panic("AAAAA");
|
||||
const south_opt = if (level.getTile(scoord)) |t| t.getCircuit() else @panic("AAAAA");
|
||||
|
||||
const north_tile = north_opt orelse world.CircuitType.None;
|
||||
const west_tile = west_opt orelse world.CircuitType.None;
|
||||
const east_tile = east_opt orelse world.CircuitType.None;
|
||||
const south_tile = south_opt orelse world.CircuitType.None;
|
||||
|
||||
const north = north_tile != .None and north_tile != .Conduit_Horizontal;
|
||||
const west = west_tile != .None and west_tile != .Conduit_Vertical;
|
||||
const east = east_tile != .None and east_tile != .Conduit_Vertical;
|
||||
const south = south_tile != .None and south_tile != .Conduit_Horizontal;
|
||||
|
||||
std.log.warn("[buildCircuit] {}: {} {},\n\t{} {},\n\t{} {},\n\t{} {}", .{
|
||||
coord,
|
||||
north_tile,
|
||||
ncoord,
|
||||
west_tile,
|
||||
wcoord,
|
||||
east_tile,
|
||||
ecoord,
|
||||
south_tile,
|
||||
scoord,
|
||||
});
|
||||
|
||||
// We don't have four way switches, don't allow them
|
||||
std.debug.assert(west != true or east != true);
|
||||
|
@ -480,7 +539,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
// Add switch outlets
|
||||
if (input_dir != .West and west) {
|
||||
const out_node = @intCast(world.NodeID, nodes.items.len);
|
||||
const new_coord = coord.add(.{-1, 0});
|
||||
const new_coord = coord.add(.{ -1, 0 });
|
||||
try nodes.append(.{
|
||||
.kind = .{ .SwitchOutlet = .{
|
||||
.source = next_node,
|
||||
|
@ -499,7 +558,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
|
||||
if (input_dir != .East and east) {
|
||||
const out_node = @intCast(world.NodeID, nodes.items.len);
|
||||
const new_coord = coord.add(.{1, 0});
|
||||
const new_coord = coord.add(.{ 1, 0 });
|
||||
try nodes.append(.{
|
||||
.kind = .{ .SwitchOutlet = .{
|
||||
.source = next_node,
|
||||
|
@ -518,7 +577,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
|
||||
if (input_dir != .South and south) {
|
||||
const out_node = @intCast(world.NodeID, nodes.items.len);
|
||||
const new_coord = coord.add(.{0, 1});
|
||||
const new_coord = coord.add(.{ 0, 1 });
|
||||
try nodes.append(.{
|
||||
.kind = .{ .SwitchOutlet = .{
|
||||
.source = next_node,
|
||||
|
@ -537,7 +596,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
|
||||
if (input_dir != .North and north) {
|
||||
const out_node = @intCast(world.NodeID, nodes.items.len);
|
||||
const new_coord = coord.add(.{0, -1});
|
||||
const new_coord = coord.add(.{ 0, -1 });
|
||||
try nodes.append(.{
|
||||
.kind = .{ .SwitchOutlet = .{
|
||||
.source = next_node,
|
||||
|
@ -596,10 +655,34 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
}
|
||||
} else {
|
||||
_ = 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;
|
||||
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||
try nodes.append(.{
|
||||
.kind = .{ .And = .{ last_node, std.math.maxInt(world.NodeID) } },
|
||||
.coord = coord,
|
||||
});
|
||||
std.log.warn("{}", .{nodes.items[last_node]});
|
||||
switch (nodes.items[last_node].kind) {
|
||||
.And => |_and| {
|
||||
if (_and[0] == std.math.maxInt(world.NodeID)) {
|
||||
nodes.items[last_node].kind.And[0] = next_node;
|
||||
} else if (_and[1] == std.math.maxInt(world.NodeID)) {
|
||||
nodes.items[last_node].kind.And[1] = next_node;
|
||||
} else {
|
||||
return error.AndGateFilled;
|
||||
}
|
||||
},
|
||||
.SwitchOutlet => |_switch| {
|
||||
_ = _switch;
|
||||
std.log.warn("{}", .{nodes.items[last_node].coord});
|
||||
},
|
||||
.Socket => |socket| {
|
||||
_ = socket;
|
||||
},
|
||||
else => return error.Unimplemented,
|
||||
}
|
||||
} else if (side == .L) {
|
||||
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||
try nodes.append(.{
|
||||
|
@ -625,7 +708,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
}
|
||||
},
|
||||
.Xor => {
|
||||
std.log.warn("XOR XOR XOR",.{});
|
||||
std.log.warn("XOR XOR XOR", .{});
|
||||
// TODO: verify Xor gate is properly connected
|
||||
const last_coord = node.data.last_coord.?;
|
||||
const Side = enum { O, L, R };
|
||||
|
@ -679,6 +762,9 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
continue;
|
||||
}
|
||||
},
|
||||
.Diode => {
|
||||
// TODO
|
||||
},
|
||||
.None => continue,
|
||||
}
|
||||
|
||||
|
@ -712,10 +798,30 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
|||
bfs_queue.append(left);
|
||||
bfs_queue.append(down);
|
||||
bfs_queue.append(up);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
const Dir = enum { North, West, East, South };
|
||||
|
||||
fn getInputDirection(coord: world.Coordinate, last_coord: world.Coordinate) Dir {
|
||||
if (last_coord.eq(coord.add(.{ 0, -1 }))) {
|
||||
return .North;
|
||||
} else if (last_coord.eq(coord.add(.{ -1, 0 }))) {
|
||||
return .West;
|
||||
} else if (last_coord.eq(coord.add(.{ 1, 0 }))) {
|
||||
return .East;
|
||||
} else {
|
||||
return .South;
|
||||
}
|
||||
}
|
||||
|
||||
fn getLevel(levels: []world.Level, x: i8, y: i8) ?world.Level {
|
||||
for (levels) |level| {
|
||||
if (level.world_x == x and level.world_y == y) return level;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue