From 85f4931a63c506aef2991037fe02a0dda6962537 Mon Sep 17 00:00:00 2001 From: Evan Burkey Date: Mon, 30 Dec 2024 14:17:13 -0800 Subject: [PATCH] init --- .gitignore | 3 + LICENSE | 5 ++ README.md | 7 ++ arch-spec | 79 ++++++++++++++++ build.zig | 24 +++++ build.zig.zon | 67 ++++++++++++++ challenge.bin | Bin 0 -> 59914 bytes src/checker.zig | 54 +++++++++++ src/main.zig | 7 ++ src/vm.zig | 235 ++++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 481 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100755 arch-spec create mode 100644 build.zig create mode 100644 build.zig.zon create mode 100644 challenge.bin create mode 100644 src/checker.zig create mode 100644 src/main.zig create mode 100644 src/vm.zig diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..322ff1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +zig-out +.zig-cache +.idea \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..de10fd4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,5 @@ +Copyright 2023 Evan Burkey + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..938e520 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Synacor Challenge + +Solution to the Synacor challenge using Zig + +## Checking Solutions + +The `checker` binary takes a solution code from the project as an argument and verifies it against known checksums of correct answers. It only works with the supplied binary `challenge.bin` \ No newline at end of file diff --git a/arch-spec b/arch-spec new file mode 100755 index 0000000..a2a1902 --- /dev/null +++ b/arch-spec @@ -0,0 +1,79 @@ +== Synacor OSCON 2012 Challenge == +In this challenge, your job is to use this architecture spec to create a +virtual machine capable of running the included binary. Along the way, +you will find codes; submit these to the challenge website to track +your progress. Good luck! + + +== architecture == +- three storage regions + - memory with 15-bit address space storing 16-bit values + - eight registers + - an unbounded stack which holds individual 16-bit values +- all numbers are unsigned integers 0..32767 (15-bit) +- all math is modulo 32768; 32758 + 15 => 5 + +== binary format == +- each number is stored as a 16-bit little-endian pair (low byte, high byte) +- numbers 0..32767 mean a literal value +- numbers 32768..32775 instead mean registers 0..7 +- numbers 32776..65535 are invalid +- programs are loaded into memory starting at address 0 +- address 0 is the first 16-bit value, address 1 is the second 16-bit value, etc + +== execution == +- After an operation is executed, the next instruction to read is immediately after the last argument of the current operation. If a jump was performed, the next operation is instead the exact destination of the jump. +- Encountering a register as an operation argument should be taken as reading from the register or setting into the register as appropriate. + +== hints == +- Start with operations 0, 19, and 21. +- Here's a code for the challenge website: LDOb7UGhTi +- The program "9,32768,32769,4,19,32768" occupies six memory addresses and should: + - Store into register 0 the sum of 4 and the value contained in register 1. + - Output to the terminal the character with the ascii code contained in register 0. + +== opcode listing == +halt: 0 + stop execution and terminate the program +set: 1 a b + set register to the value of +push: 2 a + push onto the stack +pop: 3 a + remove the top element from the stack and write it into ; empty stack = error +eq: 4 a b c + set to 1 if is equal to ; set it to 0 otherwise +gt: 5 a b c + set to 1 if is greater than ; set it to 0 otherwise +jmp: 6 a + jump to +jt: 7 a b + if is nonzero, jump to +jf: 8 a b + if is zero, jump to +add: 9 a b c + assign into the sum of and (modulo 32768) +mult: 10 a b c + store into the product of and (modulo 32768) +mod: 11 a b c + store into the remainder of divided by +and: 12 a b c + stores into the bitwise and of and +or: 13 a b c + stores into the bitwise or of and +not: 14 a b + stores 15-bit bitwise inverse of in +rmem: 15 a b + read memory at address and write it to +wmem: 16 a b + write the value from into memory at address +call: 17 a + write the address of the next instruction to the stack and jump to +ret: 18 + remove the top element from the stack and jump to it; empty stack = halt +out: 19 a + write the character represented by ascii code to the terminal +in: 20 a + read a character from the terminal and write its ascii code to ; it can be assumed that once input starts, it will continue until a newline is encountered; this means that you can safely read whole lines from the keyboard instead of having to figure out how to read individual characters +noop: 21 + no operation diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..e9dcb1a --- /dev/null +++ b/build.zig @@ -0,0 +1,24 @@ +const std = @import("std"); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const zynacor = b.addExecutable(.{ + .name = "zynacor", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + const checker = b.addExecutable(.{ + .name = "checker", + .root_source_file = b.path("src/checker.zig"), + .target = target, + .optimize = optimize, + }); + + b.installArtifact(zynacor); + b.installArtifact(checker); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..2cd2dfc --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,67 @@ +.{ + .name = "zynacor", + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. + .version = "0.0.0", + + // This field is optional. + // This is currently advisory only; Zig does not yet do anything + // with this value. + //.minimum_zig_version = "0.11.0", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. + .dependencies = .{ + // See `zig fetch --save ` for a command-line interface for adding dependencies. + //.example = .{ + // // When updating this field to a new URL, be sure to delete the corresponding + // // `hash`, otherwise you are communicating that you expect to find the old hash at + // // the new URL. + // .url = "https://example.com/foo.tar.gz", + // + // // This is computed from the file contents of the directory of files that is + // // obtained after fetching `url` and applying the inclusion rules given by + // // `paths`. + // // + // // This field is the source of truth; packages do not come from a `url`; they + // // come from a `hash`. `url` is just one of many possible mirrors for how to + // // obtain a package matching this `hash`. + // // + // // Uses the [multihash](https://multiformats.io/multihash/) format. + // .hash = "...", + // + // // When this is provided, the package is found in a directory relative to the + // // build root. In this case the package's hash is irrelevant and therefore not + // // computed. This field and `url` are mutually exclusive. + // .path = "foo", + + // // When this is set to `true`, a package is declared to be lazily + // // fetched. This makes the dependency only get fetched if it is + // // actually used. + // .lazy = false, + //}, + }, + + // Specifies the set of files and directories that are included in this package. + // Only files and directories listed here are included in the `hash` that + // is computed for this package. + // Paths are relative to the build root. Use the empty string (`""`) to refer to + // the build root itself. + // A directory listed here means that all files within, recursively, are included. + .paths = .{ + // This makes *all* files, recursively, included in this package. It is generally + // better to explicitly list the files and directories instead, to insure that + // fetching from tarballs, file system paths, and version control all result + // in the same contents hash. + "", + // For example... + //"build.zig", + //"build.zig.zon", + //"src", + //"LICENSE", + //"README.md", + }, +} diff --git a/challenge.bin b/challenge.bin new file mode 100644 index 0000000000000000000000000000000000000000..6e653f96af832688fe5f97c6239134cfb1587fb5 GIT binary patch literal 59914 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 literal 0 HcmV?d00001 diff --git a/src/checker.zig b/src/checker.zig new file mode 100644 index 0000000..1ffa8f2 --- /dev/null +++ b/src/checker.zig @@ -0,0 +1,54 @@ +const std = @import("std"); + +const sums: [8][]const u8 = .{ + "76ec2408e8fe3f1753c25db51efd8eb3", + "0e6aa7be1f68d930926d72b3741a145c", + "7997a3b2941eab92c1c0345d5747b420", + "186f842951c0dcfe8838af1e7222b7d4", + "2bf84e54b95ce97aefd9fc920451fc45", + "e09640936b3ef532b7b8e83ce8f125f4", + "4873cf6b76f62ac7d5a53605b2535a0c", + "d0c54d4ed7f943280ce3e19532dbb1a6" +}; + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}).init; + const allocator = gpa.allocator(); + var args = try std.process.argsWithAllocator(allocator); + defer args.deinit(); + + var input: []const u8 = undefined; + + // Skip arg[0] + _ = args.skip(); + + const argVal = args.next(); + if (argVal) |a| { + input = a; + } else { + std.debug.print("USAGE: checker ANSWER\n", .{}); + std.process.exit(1); + } + + var hasher = std.crypto.hash.Md5.init(.{}); + var buf: [std.crypto.hash.Md5.digest_length]u8 = undefined; + hasher.update(input); + hasher.final(buf[0..]); + const digest = try std.fmt.allocPrint(allocator, "{x}", .{std.fmt.fmtSliceHexLower(&buf)}); + + var matched = false; + for (sums, 0..) |sum, i| { + if (std.mem.eql(u8, digest, sum)) { + std.debug.print("CORRECT! {s} matches sum #{d}: {s}\n", .{input, i, sum}); + matched = true; + break; + } + } + + if (!matched) { + std.debug.print("FAILURE! {s} matches no sums\n", .{input}); + } + + allocator.free(digest); +} + diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..5dcd8e3 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,7 @@ +const vm = @import("vm.zig"); + +pub fn main() !void { + var v = try vm.init(); + try v.run(); +} + diff --git a/src/vm.zig b/src/vm.zig new file mode 100644 index 0000000..4c1789b --- /dev/null +++ b/src/vm.zig @@ -0,0 +1,235 @@ +const std = @import("std"); + +const maxMemory = 0x8000; +const regSize = 8; +const maxStackSize= 32; +const regStart = 32768; +const regEnd = 32775; + +const VmState = enum { + Reset, + Running, + Paused, + Halted, + Error, + AwaitingInput, +}; + +const VmError = error { + PoppedEmptyStack, + PushedMaxStack, + InvalidAddress, + InvalidRegValue, + Unknown, +}; + +pub const Vm = struct { + mem: [maxMemory]u16, + reg: [regSize]u16, + pc: u16, + + stack: [maxStackSize]u16, + stackSize: usize, + + inputBuffer: std.ArrayList(u8), + + allocator: std.mem.Allocator, + state: VmState, + + const outWriter = std.io.getStdOut().writer(); + const inReader = std.io.getStdIn().reader(); + + fn pop(self: *Vm) VmError!u16 { + if (self.stackSize == 0) { + return VmError.PoppedEmptyStack; + } + const v = self.stack[self.stackSize - 1]; + self.stackSize -= 1; + return v; + } + + fn push(self: *Vm, v: u16) !void { + if (self.stackSize == maxStackSize) { + return VmError.PushedMaxStack; + } + self.stack[self.stackSize] = v; + self.stackSize += 1; + } + + fn getVal(self: *Vm, o: u16) !u16 { + const val = self.mem[self.pc + o]; + if (val < regStart) { + return val; + } else if (val <= regEnd) { + return self.reg[val - regStart]; + } + return VmError.InvalidAddress; + } + + fn getReg(self: *Vm, o: u16) !*u16 { + const val = self.mem[self.pc + o]; + if (val < regStart or val > regEnd) { + return VmError.InvalidRegValue; + } + return &self.reg[val - regStart]; + } + + pub fn run(self: *Vm) !void { + self.state = VmState.Running; + while (self.state == VmState.Running) { + switch (self.mem[self.pc]) { + // halt: 0 + 0 => self.state = VmState.Halted, + // set: 1 a b + 1 => { + const r = try self.getReg(1); + r.* = try self.getVal(2); + self.pc += 3; + }, + // push: 2 a + 2 => { + try self.push(try self.getVal(1)); + self.pc += 2; + }, + // pop: 3 a + 3 => { + const r = try self.getReg(1); + r.* = try self.pop(); + self.pc += 2; + }, + // eq: 4 a b c + 4 => { + const r = try self.getReg(1); + r.* = if (try self.getVal(2) == try self.getVal(3)) 1 else 0; + self.pc += 4; + }, + // gt: 5 a b c + 5 => { + const r = try self.getReg(1); + r.* = if (try self.getVal(2) > try self.getVal(3)) 1 else 0; + self.pc += 4; + }, + // jmp: 6 a + 6 => self.pc = self.mem[self.pc + 1], + // jt: 7 a b + 7 => self.pc = if (try self.getVal(1) != 0) try self.getVal(2) else self.pc + 3, + // jf: 8 a b + 8 => self.pc = if (try self.getVal(1) == 0) try self.getVal(2) else self.pc + 3, + // add: 9 a b c + 9 => { + const r = try self.getReg(1); + r.* = (try self.getVal(2) +% try self.getVal(3)) % regStart; + self.pc += 4; + }, + // mult: 10 a b c + 10 => { + const r = try self.getReg(1); + r.* = (try self.getVal(2) *% try self.getVal(3)) % regStart; + self.pc += 4; + }, + // mod: 11 a b c + 11 => { + const r = try self.getReg(1); + r.* = (try self.getVal(2) % try self.getVal(3)); + self.pc += 4; + }, + // and: 12 a b c + 12 => { + const r = try self.getReg(1); + r.* = (try self.getVal(2) & try self.getVal(3)); + self.pc += 4; + }, + // or: 13 a b c + 13 => { + const r = try self.getReg(1); + r.* = (try self.getVal(2) | try self.getVal(3)); + self.pc += 4; + }, + // not: 14 a b + 14 => { + const r = try self.getReg(1); + r.* = ~(try self.getVal(2)) & 0x7FFF; + self.pc += 3; + }, + // rmem: 15 a b + 15 => { + const r = try self.getReg(1); + const b: usize = @intCast(try self.getVal(2)); + r.* = self.mem[b]; + self.pc += 3; + }, + // wmem: 16 a b + 16 => { + self.mem[try self.getVal(1)] = try self.getVal(2); + self.pc += 3; + }, + // call: 17 a + 17 => { + try self.push(self.pc + 2); + self.pc = try self.getVal(1); + }, + // ret: 18 + 18 => self.pc = try self.pop(), + // out: 19 a + 19 => { + const a: u8 = @intCast(try self.getVal(1)); + try outWriter.print("{c}", .{a}); + self.pc += 2; + }, + // in: 20 a + 20 => { + if (self.inputBuffer.items.len == 0) { + self.inputBuffer = std.ArrayList(u8).init(self.allocator); + try inReader.streamUntilDelimiter(self.inputBuffer.writer(), '\n', null); + try self.inputBuffer.append('\n'); + } + const r = try self.getReg(1); + r.* = self.inputBuffer.items[0]; + _ = self.inputBuffer.orderedRemove(0); + if (self.inputBuffer.items.len == 0) { + self.inputBuffer.deinit(); + } + self.pc += 2; + }, + // noop: 21 + 21 => self.pc += 1, + else => { + try outWriter.print("Unknown opcode {d}\n", .{self.mem[self.pc]}); + self.state = VmState.Error; + } + } + } + } +}; + +pub fn init() !Vm { + var vm = Vm { + .mem = [_]u16{0} ** maxMemory, + .reg = [_]u16{0} ** regSize, + .pc = 0, + .stack = [_]u16{0} ** maxStackSize, + .stackSize = 0, + .allocator = std.heap.GeneralPurposeAllocator(.{}).init.backing_allocator, + .state = VmState.Reset, + .inputBuffer = undefined, + }; + + const cwd = std.fs.cwd(); + const fp = try cwd.openFile("challenge.bin", .{}); + defer fp.close(); + + const sz = (try fp.stat()).size; + const buf = try fp.readToEndAlloc(vm.allocator, sz); + defer vm.allocator.free(buf); + + var i: usize = 0; + var j: usize = 0; + while (i < sz) : (i += 2) { + const a: u16 = @intCast(buf[i]); + const b: u16 = @intCast(buf[i+1]); + vm.mem[j] = a | (b << 8); + j += 1; + } + + return vm; +}