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