Read and write circuit nodes
parent
c086c6d9de
commit
020e6f3615
176
src/world.zig
176
src/world.zig
|
@ -151,6 +151,18 @@ pub const Coordinate = struct {
|
||||||
return Coordinate{ .val = val };
|
return Coordinate{ .val = val };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read(reader: anytype) !Coordinate {
|
||||||
|
return Coordinate{ .val = .{
|
||||||
|
try reader.readInt(i16, .Little),
|
||||||
|
try reader.readInt(i16, .Little),
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(coord: Coordinate, writer: anytype) !void {
|
||||||
|
try writer.writeInt(i16, coord.val[0], .Little);
|
||||||
|
try writer.writeInt(i16, coord.val[1], .Little);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add(coord: Coordinate, val: [2]i16) Coordinate {
|
pub fn add(coord: Coordinate, val: [2]i16) Coordinate {
|
||||||
return .{ .val = .{ coord.val[0] + val[0], coord.val[1] + val[1] } };
|
return .{ .val = .{ coord.val[0] + val[0], coord.val[1] + val[1] } };
|
||||||
}
|
}
|
||||||
|
@ -463,8 +475,7 @@ pub const Entity = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Data format:
|
// Data format:
|
||||||
// | node count | level count |
|
// | level count | node count |
|
||||||
// | node headers... |
|
|
||||||
// | level headers... |
|
// | level headers... |
|
||||||
// | node data... |
|
// | node data... |
|
||||||
// | level data... |
|
// | level data... |
|
||||||
|
@ -489,34 +500,40 @@ pub const LevelHeader = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn write(level_headers: []LevelHeader, writer: anytype) !void {
|
pub fn write(
|
||||||
|
writer: anytype,
|
||||||
|
level_headers: []LevelHeader,
|
||||||
|
circuit_nodes: []CircuitNode,
|
||||||
|
levels: []Level,
|
||||||
|
) !void {
|
||||||
// Write number of levels
|
// Write number of levels
|
||||||
try writer.writeInt(u16, @intCast(u16, level_headers.len), .Little);
|
try writer.writeInt(u16, @intCast(u16, level_headers.len), .Little);
|
||||||
|
// Write number of circuit nodes
|
||||||
|
try writer.writeInt(u16, @intCast(u16, circuit_nodes.len), .Little);
|
||||||
|
|
||||||
// Write headers
|
// Write headers
|
||||||
for (level_headers) |lvl_header| {
|
for (level_headers) |lvl_header| {
|
||||||
try lvl_header.write(writer);
|
try lvl_header.write(writer);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(alloc: std.mem.Allocator, reader: anytype) ![]LevelHeader {
|
// Write node data
|
||||||
// read number of levels
|
for (circuit_nodes) |node| {
|
||||||
const level_count = try reader.readInt(u16, .Little);
|
try node.write(writer);
|
||||||
|
|
||||||
var level_headers = try alloc.alloc(LevelHeader, level_count);
|
|
||||||
// read headers
|
|
||||||
for (level_headers) |_, i| {
|
|
||||||
level_headers[i] = try LevelHeader.read(reader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return level_headers;
|
// Write levels
|
||||||
|
for (levels) |level| {
|
||||||
|
try level.write(writer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cursor = std.io.FixedBufferStream([]const u8);
|
const Cursor = std.io.FixedBufferStream([]const u8);
|
||||||
pub const Database = struct {
|
pub const Database = struct {
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
level_info: []LevelHeader,
|
level_info: []LevelHeader,
|
||||||
|
circuit_info: []CircuitNode,
|
||||||
level_data_begin: usize,
|
level_data_begin: usize,
|
||||||
|
// circuit_data_begin: usize,
|
||||||
|
|
||||||
const world_data = @embedFile(@import("world_data").path);
|
const world_data = @embedFile(@import("world_data").path);
|
||||||
|
|
||||||
|
@ -528,12 +545,31 @@ pub const Database = struct {
|
||||||
|
|
||||||
var reader = cursor.reader();
|
var reader = cursor.reader();
|
||||||
|
|
||||||
var levels = try read(alloc, reader);
|
// read number of levels
|
||||||
|
const level_count = try reader.readInt(u16, .Little);
|
||||||
|
// read number of nodes
|
||||||
|
const node_count = try reader.readInt(u16, .Little);
|
||||||
|
|
||||||
|
var level_headers = try alloc.alloc(LevelHeader, level_count);
|
||||||
|
|
||||||
|
// read headers
|
||||||
|
for (level_headers) |_, i| {
|
||||||
|
level_headers[i] = try LevelHeader.read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
var circuit_nodes = try alloc.alloc(CircuitNode, node_count);
|
||||||
|
|
||||||
|
// read headers
|
||||||
|
for (circuit_nodes) |_, i| {
|
||||||
|
circuit_nodes[i] = try CircuitNode.read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
var level_data_begin = @intCast(usize, try cursor.getPos());
|
var level_data_begin = @intCast(usize, try cursor.getPos());
|
||||||
|
|
||||||
return Database{
|
return Database{
|
||||||
.cursor = cursor,
|
.cursor = cursor,
|
||||||
.level_info = levels,
|
.level_info = level_headers,
|
||||||
|
.circuit_info = circuit_nodes,
|
||||||
.level_data_begin = level_data_begin,
|
.level_data_begin = level_data_begin,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -586,13 +622,25 @@ pub const Database = struct {
|
||||||
// An abstract representation of all circuits in game.
|
// An abstract representation of all circuits in game.
|
||||||
// abstract_circuit: []CircuitNode,
|
// abstract_circuit: []CircuitNode,
|
||||||
|
|
||||||
const NodeID = u16;
|
pub const NodeID = u8;
|
||||||
|
|
||||||
pub const CircuitNode = struct {
|
pub const CircuitNode = struct {
|
||||||
energized: bool = false,
|
energized: bool = false,
|
||||||
kind: NodeKind,
|
kind: NodeKind,
|
||||||
coord: Coordinate,
|
coord: Coordinate,
|
||||||
|
|
||||||
|
pub fn read(reader: anytype) !CircuitNode {
|
||||||
|
return CircuitNode{
|
||||||
|
.coord = try Coordinate.read(reader),
|
||||||
|
.kind = try NodeKind.read(reader),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(node: CircuitNode, writer: anytype) !void {
|
||||||
|
try node.coord.write(writer);
|
||||||
|
try node.kind.write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn format(node: CircuitNode, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
pub fn format(node: CircuitNode, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
_ = options;
|
_ = options;
|
||||||
if (fmt.len != 0) @compileError("Unknown format character: '" ++ fmt ++ "'");
|
if (fmt.len != 0) @compileError("Unknown format character: '" ++ fmt ++ "'");
|
||||||
|
@ -604,7 +652,18 @@ pub const CircuitNode = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const NodeKind = union(enum) {
|
const NodeEnum = enum(u4) {
|
||||||
|
And,
|
||||||
|
Xor,
|
||||||
|
Source,
|
||||||
|
Conduit,
|
||||||
|
Plug,
|
||||||
|
Switch,
|
||||||
|
Join,
|
||||||
|
Outlet,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const NodeKind = union(NodeEnum) {
|
||||||
/// An And logic gate
|
/// An And logic gate
|
||||||
And: [2]NodeID,
|
And: [2]NodeID,
|
||||||
/// A Xor logic gate
|
/// A Xor logic gate
|
||||||
|
@ -621,10 +680,91 @@ pub const NodeKind = union(enum) {
|
||||||
/// Vertical = Off or Top/Bottom, depending on flow
|
/// Vertical = Off or Top/Bottom, depending on flow
|
||||||
/// Horizontal = Off or Left/Right, depending on flow
|
/// Horizontal = Off or Left/Right, depending on flow
|
||||||
/// Tee = Top/Bottom or Left/Right, depending on flow
|
/// Tee = Top/Bottom or Left/Right, depending on flow
|
||||||
Switch: enum { Off, Bottom, Top, Left, Right },
|
Switch: SwitchEnum,
|
||||||
Join: NodeID,
|
Join: NodeID,
|
||||||
Outlet: NodeID,
|
Outlet: NodeID,
|
||||||
|
|
||||||
|
const SwitchEnum = enum { Off, Bottom, Top, Left, Right };
|
||||||
|
|
||||||
|
pub fn read(reader: anytype) !NodeKind {
|
||||||
|
var kind: NodeKind = undefined;
|
||||||
|
const nodeEnum = @intToEnum(NodeEnum, try reader.readInt(u8, .Little));
|
||||||
|
switch (nodeEnum) {
|
||||||
|
.And => {
|
||||||
|
kind = .{ .And = .{
|
||||||
|
try reader.readInt(NodeID, .Little),
|
||||||
|
try reader.readInt(NodeID, .Little),
|
||||||
|
} };
|
||||||
|
},
|
||||||
|
.Xor => {
|
||||||
|
kind = .{ .Xor = .{
|
||||||
|
try reader.readInt(NodeID, .Little),
|
||||||
|
try reader.readInt(NodeID, .Little),
|
||||||
|
} };
|
||||||
|
},
|
||||||
|
.Source => kind = .Source,
|
||||||
|
.Conduit => {
|
||||||
|
kind = .{ .Conduit = .{
|
||||||
|
try reader.readInt(NodeID, .Little),
|
||||||
|
try reader.readInt(NodeID, .Little),
|
||||||
|
} };
|
||||||
|
},
|
||||||
|
.Plug => {
|
||||||
|
const plug =
|
||||||
|
try reader.readInt(NodeID, .Little);
|
||||||
|
if (plug == std.math.maxInt(NodeID)) {
|
||||||
|
kind = .{ .Plug = null };
|
||||||
|
} else {
|
||||||
|
kind = .{ .Plug = plug };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.Switch => {
|
||||||
|
kind = .{
|
||||||
|
.Switch = @intToEnum(SwitchEnum, try reader.readInt(NodeID, .Little)),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.Join => {
|
||||||
|
kind = .{ .Join = try reader.readInt(NodeID, .Little) };
|
||||||
|
},
|
||||||
|
.Outlet => {
|
||||||
|
kind = .{ .Outlet = try reader.readInt(NodeID, .Little) };
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(kind: NodeKind, writer: anytype) !void {
|
||||||
|
try writer.writeInt(u8, @enumToInt(kind), .Little);
|
||||||
|
switch (kind) {
|
||||||
|
.And => |And| {
|
||||||
|
try writer.writeInt(NodeID, And[0], .Little);
|
||||||
|
try writer.writeInt(NodeID, And[1], .Little);
|
||||||
|
},
|
||||||
|
.Xor => |Xor| {
|
||||||
|
try writer.writeInt(NodeID, Xor[0], .Little);
|
||||||
|
try writer.writeInt(NodeID, Xor[1], .Little);
|
||||||
|
},
|
||||||
|
.Source => {},
|
||||||
|
.Conduit => |Conduit| {
|
||||||
|
try writer.writeInt(NodeID, Conduit[0], .Little);
|
||||||
|
try writer.writeInt(NodeID, Conduit[1], .Little);
|
||||||
|
},
|
||||||
|
.Plug => |Plug| {
|
||||||
|
const plug = Plug orelse std.math.maxInt(NodeID);
|
||||||
|
try writer.writeInt(NodeID, plug, .Little);
|
||||||
|
},
|
||||||
|
.Switch => |Switch| {
|
||||||
|
try writer.writeInt(NodeID, @enumToInt(Switch), .Little);
|
||||||
|
},
|
||||||
|
.Join => |Join| {
|
||||||
|
try writer.writeInt(NodeID, Join, .Little);
|
||||||
|
},
|
||||||
|
.Outlet => |Outlet| {
|
||||||
|
try writer.writeInt(NodeID, Outlet, .Little);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn format(kind: NodeKind, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
pub fn format(kind: NodeKind, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
_ = options;
|
_ = options;
|
||||||
if (fmt.len != 0) @compileError("Unknown format character: '" ++ fmt ++ "'");
|
if (fmt.len != 0) @compileError("Unknown format character: '" ++ fmt ++ "'");
|
||||||
|
|
|
@ -109,12 +109,7 @@ fn make(step: *std.build.Step) !void {
|
||||||
defer data.deinit();
|
defer data.deinit();
|
||||||
const writer = data.writer();
|
const writer = data.writer();
|
||||||
|
|
||||||
try world.write(level_headers.items, writer);
|
try world.write(writer, level_headers.items, circuit.items, levels.items);
|
||||||
|
|
||||||
// Write levels
|
|
||||||
for (levels.items) |level| {
|
|
||||||
try level.write(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open output file and write data into it
|
// Open output file and write data into it
|
||||||
cwd.makePath(this.builder.getInstallPath(.lib, "")) catch |e| switch (e) {
|
cwd.makePath(this.builder.getInstallPath(.lib, "")) catch |e| switch (e) {
|
||||||
|
@ -283,7 +278,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
const SearchItem = struct {
|
const SearchItem = struct {
|
||||||
coord: Coord,
|
coord: Coord,
|
||||||
last_coord: ?Coord = null,
|
last_coord: ?Coord = null,
|
||||||
last_node: u16,
|
last_node: world.NodeID,
|
||||||
};
|
};
|
||||||
const Queue = std.TailQueue(SearchItem);
|
const Queue = std.TailQueue(SearchItem);
|
||||||
const Node = Queue.Node;
|
const Node = Queue.Node;
|
||||||
|
@ -309,7 +304,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
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 coordinate = try alloc.create(Node);
|
||||||
coordinate.* = .{ .data = .{
|
coordinate.* = .{ .data = .{
|
||||||
.last_node = @intCast(u16, nodes.items.len),
|
.last_node = @intCast(world.NodeID, nodes.items.len),
|
||||||
.coord = Coord.init(.{ x, y }),
|
.coord = Coord.init(.{ x, y }),
|
||||||
} };
|
} };
|
||||||
switch (tileData) {
|
switch (tileData) {
|
||||||
|
@ -324,7 +319,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
},
|
},
|
||||||
.Plug => {
|
.Plug => {
|
||||||
// try nodes.append(.{ .kind = .{ .Plug = null } });
|
// try nodes.append(.{ .kind = .{ .Plug = null } });
|
||||||
coordinate.data.last_node = 20000;
|
coordinate.data.last_node = std.math.maxInt(world.NodeID);
|
||||||
plugs.append(coordinate);
|
plugs.append(coordinate);
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
|
@ -370,21 +365,22 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
const flags = tile.flags;
|
const flags = tile.flags;
|
||||||
|
|
||||||
switch (flags.circuit) {
|
switch (flags.circuit) {
|
||||||
.Source, .Conduit => {
|
.Source => {}, // Do nothing, but add everything around the 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 => {
|
||||||
// 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(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .Plug = null },
|
.kind = .{ .Plug = null },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.Outlet => {
|
.Outlet => {
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .Outlet = last_node },
|
.kind = .{ .Outlet = last_node },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
|
@ -392,7 +388,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
},
|
},
|
||||||
.Switch_Off => {
|
.Switch_Off => {
|
||||||
// TODO: Find last coordinate of search and determine flow
|
// TODO: Find last coordinate of search and determine flow
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .Switch = .Off },
|
.kind = .{ .Switch = .Off },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
|
@ -400,7 +396,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
},
|
},
|
||||||
.Switch_On => {
|
.Switch_On => {
|
||||||
// TODO: Find last coordinate of search and determine flow
|
// TODO: Find last coordinate of search and determine flow
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .Switch = .Off },
|
.kind = .{ .Switch = .Off },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
|
@ -412,7 +408,7 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
std.log.warn("Join first side", .{});
|
std.log.warn("Join first side", .{});
|
||||||
} else {
|
} else {
|
||||||
std.log.warn("Join second side", .{});
|
std.log.warn("Join second side", .{});
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .Join = last_node },
|
.kind = .{ .Join = last_node },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
|
@ -452,15 +448,15 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
// may have come from a plug
|
// 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(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .And = .{ last_node, 20000 } },
|
.kind = .{ .And = .{ last_node, std.math.maxInt(world.NodeID) } },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
});
|
});
|
||||||
} else if (side == .R) {
|
} else if (side == .R) {
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .And = .{ 20000, last_node } },
|
.kind = .{ .And = .{ std.math.maxInt(world.NodeID), last_node } },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -498,15 +494,15 @@ pub fn buildCircuit(alloc: std.mem.Allocator, levels: []world.Level) !std.ArrayL
|
||||||
// may have come from a plug
|
// 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(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .Xor = .{ last_node, 20000 } },
|
.kind = .{ .Xor = .{ last_node, std.math.maxInt(world.NodeID) } },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
});
|
});
|
||||||
} else if (side == .R) {
|
} else if (side == .R) {
|
||||||
next_node = @intCast(u16, nodes.items.len);
|
next_node = @intCast(world.NodeID, nodes.items.len);
|
||||||
try nodes.append(.{
|
try nodes.append(.{
|
||||||
.kind = .{ .Xor = .{ 20000, last_node } },
|
.kind = .{ .Xor = .{ std.math.maxInt(world.NodeID), last_node } },
|
||||||
.coord = coord,
|
.coord = coord,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue