From dbe5a293ed0f870fc014d02d652d5c7940dc328a Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Fri, 6 Jan 2023 10:33:03 -0700 Subject: [PATCH 1/9] feat: add in-progress zig game --- .gitignore | 4 ++ games/punderplay/build.zig | 28 ++++++++++++ games/punderplay/deps.zig | 86 +++++++++++++++++++++++++++++++++++ games/punderplay/src/game.zig | 64 ++++++++++++++++++++++++++ games/punderplay/src/main.zig | 65 ++++++++++++++++++++++++++ games/punderplay/zigmod.lock | 2 + games/punderplay/zigmod.yml | 6 +++ 7 files changed, 255 insertions(+) create mode 100644 games/punderplay/build.zig create mode 100644 games/punderplay/deps.zig create mode 100644 games/punderplay/src/game.zig create mode 100644 games/punderplay/src/main.zig create mode 100644 games/punderplay/zigmod.lock create mode 100644 games/punderplay/zigmod.yml diff --git a/.gitignore b/.gitignore index 7b351ed..b64271b 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,7 @@ npm-debug.log dev.secret.exs priv/static/uploads + +games/punderplay/zig-cache/ +games/punderplay/zig-out/ +games/punderplay/.zigmod diff --git a/games/punderplay/build.zig b/games/punderplay/build.zig new file mode 100644 index 0000000..64ab473 --- /dev/null +++ b/games/punderplay/build.zig @@ -0,0 +1,28 @@ +const std = @import("std"); +const deps = @import("deps.zig"); + +pub fn build(b: *std.build.Builder) void { + const mode = b.standardReleaseOptions(); + const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding } }); + const exe = b.addExecutable("punderplay", "src/main.zig"); + exe.setTarget(target); + exe.setBuildMode(mode); + deps.addAllTo(exe); + exe.install(); + + const run_cmd = exe.run(); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + const exe_tests = b.addTest("src/main.zig"); + exe_tests.setTarget(target); + exe_tests.setBuildMode(mode); + + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&exe_tests.step); +} diff --git a/games/punderplay/deps.zig b/games/punderplay/deps.zig new file mode 100644 index 0000000..3a31f70 --- /dev/null +++ b/games/punderplay/deps.zig @@ -0,0 +1,86 @@ +// zig fmt: off +const std = @import("std"); +const builtin = @import("builtin"); +const Pkg = std.build.Pkg; +const string = []const u8; + +pub const cache = ".zigmod/deps"; + +pub fn addAllTo(exe: *std.build.LibExeObjStep) void { + checkMinZig(builtin.zig_version, exe); + @setEvalBranchQuota(1_000_000); + for (packages) |pkg| { + exe.addPackage(pkg.pkg.?); + } + var llc = false; + var vcpkg = false; + inline for (comptime std.meta.declarations(package_data)) |decl| { + const pkg = @as(Package, @field(package_data, decl.name)); + for (pkg.system_libs) |item| { + exe.linkSystemLibrary(item); + llc = true; + } + for (pkg.frameworks) |item| { + if (!std.Target.current.isDarwin()) @panic(exe.builder.fmt("a dependency is attempting to link to the framework {s}, which is only possible under Darwin", .{item})); + exe.linkFramework(item); + llc = true; + } + inline for (pkg.c_include_dirs) |item| { + exe.addIncludePath(@field(dirs, decl.name) ++ "/" ++ item); + llc = true; + } + inline for (pkg.c_source_files) |item| { + exe.addCSourceFile(@field(dirs, decl.name) ++ "/" ++ item, pkg.c_source_flags); + llc = true; + } + vcpkg = vcpkg or pkg.vcpkg; + } + if (llc) exe.linkLibC(); + if (builtin.os.tag == .windows and vcpkg) exe.addVcpkgPaths(.static) catch |err| @panic(@errorName(err)); +} + +pub const Package = struct { + directory: string, + pkg: ?Pkg = null, + c_include_dirs: []const string = &.{}, + c_source_files: []const string = &.{}, + c_source_flags: []const string = &.{}, + system_libs: []const string = &.{}, + frameworks: []const string = &.{}, + vcpkg: bool = false, +}; + +fn checkMinZig(current: std.SemanticVersion, exe: *std.build.LibExeObjStep) void { + const min = std.SemanticVersion.parse("null") catch return; + if (current.order(min).compare(.lt)) @panic(exe.builder.fmt("Your Zig version v{} does not meet the minimum build requirement of v{}", .{current, min})); +} + +pub const dirs = struct { + pub const _root = ""; + pub const _f0fex8nt61gp = cache ++ "/../.."; + pub const _hybfpvr9c5u2 = cache ++ "/git/github.com/extism/zig-pdk"; +}; + +pub const package_data = struct { + pub const _f0fex8nt61gp = Package{ + .directory = dirs._f0fex8nt61gp, + }; + pub const _hybfpvr9c5u2 = Package{ + .directory = dirs._hybfpvr9c5u2, + .pkg = Pkg{ .name = "extism-pdk", .source = .{ .path = dirs._hybfpvr9c5u2 ++ "/src/main.zig" }, .dependencies = null }, + }; + pub const _root = Package{ + .directory = dirs._root, + }; +}; + +pub const packages = &[_]Package{ + package_data._hybfpvr9c5u2, +}; + +pub const pkgs = struct { + pub const extism_pdk = package_data._hybfpvr9c5u2; +}; + +pub const imports = struct { +}; diff --git a/games/punderplay/src/game.zig b/games/punderplay/src/game.zig new file mode 100644 index 0000000..cf00d7f --- /dev/null +++ b/games/punderplay/src/game.zig @@ -0,0 +1,64 @@ +const std = @import("std"); +const Plugin = @import("extism-pdk").Plugin; + +pub const Player = []const u8; +pub const Judge = Player; +pub const Scores = std.StringHashMap(u8); +pub const Round = struct { + winner: Player, + winning_pun: []const u8, + judge: Judge, + prompt: [2]u8, +}; + +const Game = struct { + allocator: std.mem.Allocator, + current_judge: Judge, + players: []Player, + scores: Scores, + rounds: std.ArrayList(Round), + + const Self = @This(); + + pub fn init(allocator: std.mem.Allocator, players: []Player) Self { + // pick a player from the set of current players to act as the judge. + // initialize the scores for each player. + var scores = std.StringHashMap(u8).init(allocator); + for (players) |player| { + scores.put(player, 0) catch unreachable; + } + return Self{ + .allocator = allocator, + .current_judge = players[0], + .players = players, + .scores = scores, + .rounds = std.ArrayList(Round).init(allocator), + }; + } + + pub fn deinit(self: *Self) void { + self.scores.deinit(); + self.rounds.deinit(); + } +}; + +const verbs = "watering.cataloging.hunting.wanting.holding.taping.integrating.worrying.loving.spending.fitting.bating.risking.normalizing.restructuring.costing.programming.touching.towing.altering.marketing.yelling.crushing.beholding.agreeing.fencing.sparkling.wiping.sparking.slaying.copying.melting.appraising.complaining.leading.telling.crashing.subtracting.normalizing.grabbing.wrecking.thanking.forming.answering.overhearing.wriggling.rin.ing.admitting.bruising.making.pumping.melting.bumping.dragging.consisting.accepting.dropping.smelling.recognizing.facing.deciding.deserting.riding.ensuring.frightening.shading.flapping.washing.completing.heaping.snoring.draining.clothing.detailing.initiating.dispensing.diagnosing.paddling.sin.ing.promising.handling.planing.separating.thriving.shrinking.scrubbing.confusing.spotting.scattering.noticing.upgrading.piloting.estimating.showing.reigning.folding.contracting.blushing.broadcasting.speaking.slipping.squashing.pecking.hanging.returning.receiving.landing.injecting.fleeing.cheering.sniffing.sleeping.clin.ing.breeding.searching.carving.meaning.attaching.affording.nesting.undergoing.passing.entertaining.longing.enjoying.fighting.wrestling.unfastening.drawing.supposing.knotting.greasing.producing.spinning.squashing.asking.projecting.enduring.adopting.fancying.conducting.conceiving.guessing.mating.overthrowing.regulating.determining.bearing.devising.abiding.piloting.hearing.rhyming.retrieving.servicing.integrating.preaching.rubbing.clarifying.agreeing.striking.wobbling.groaning.speeding.filling.repairing.pining.launching.sneaking.shaping.breathing.spoiling.living.recruiting.proposing.pedaling.wrecking.replacing.operating.trying.licensing.discovering.overdoing.rinsing.camping.displaying.muddling.pricking.nesting.processing.counseling.consolidating.shivering.numbering.removing.sliding.referring.rin.ing.representing.risking.inspecting.assisting.enhancing.administering.identifying.enacting.skipping.shaking.spoiling.spelling.selecting.shopping.causing.reflecting.photographing.withstanding.evaluating.breaking.visiting.creeping.feeding.loading.graduating.combing.tickling.catching.dividing.squealing.breathing.fixing.floating.logging.chewing.carrying.hurting.sacking.expressing.getting.forbidding.sawing.moaning.grinding.ruining.hurrying.balancing.exploding.spilling.welcoming.eliminating.acceding.classifying.smiling.assuring.settling.scheduling.perceiving.moaning.shooting.reconciling.faxing.executing.decaying.marrying.stin.ing.investigating.enacting.caring.questioning.proving.rescuing.filming.shopping.separating.identifying.leading.laying.speeding.tracing.identifying.alerting.sacking.remaining.activating.interesting.boasting.imagining.putting.controlling.disliking.addressing.solving.fleeing.agreeing.shining.fancying.wrin.ing.fading.accelerating.establishing.curling.attacking.guaranteeing.deceiving.patting.applauding.noting.pressing.kneeling.hitting.scheduling.presiding.repeating.prescribing.arising.slaying.adding.fitting.snoring.shaking.sewing.inspecting.educating.manipulating.belonging.giving.participating.agreeing.doubting.misunderstanding.following.trotting.writing.clin.ing.interesting.damming.correlating.plugging.attending.retiring.beholding.understanding.walking.pinpointing.photographing.braking.soaking.folding.remembering.slin.ing.borrowing.rocking.allowing.filming.obeying.coiling.cycling.untidying.shrinking.preferring.stirring.fixing.attending.baking.saying.rotting.learning.governing.confessing.reminding.utilizing.bruising.dramatizing.knowing.puncturing.shearing.suggesting.achieving.heading.sliding.punching.greeting.gazing.swin.ing.spending.occurring.sneezing.creating.sparking.hiding.stitching.promoting.changing.snowing.taking.lying.reading.responding.bouncing.baking.pecking.multiplying.conserving.challenging.losing.sowing.fooling.marketing.informing.spilling.matching.speaking.dealing.detecting.rating.screwing.bruising.interlaying.phoning.ensuring.binding.stoping.scattering.weighing.participating.editing.letting.publicizing.preparing.financing.shearing.checking.writing.exciting.firing.bombing.disliking.restoring.eating.fighting.answering.balancing.sending.blotting.amusing.disagreeing.innovating.relying.correcting.confronting.judging.reducing.entertaining.arguing.selecting.stamping.parking.naming.noticing.doing.chopping.banging.engineering.trusting.describing.delegating.cheating.lending.mistaking.squeaking.winding.comparing.adapting.cracking.correlating.scolding.blushing.scraping.buzzing.existing.improvising.praising.splitting.distributing.curing.overdoing.mapping.progressing.activating.feeding.forgiving.dressing.manning.polishing.smoking.reconciling.knowing.tugging.being.causing.shutting.preventing.disappearing.presenting.banging.explaining.crossing.predicting.converting.sighing.designing.fooling.bursting.decorating.battling.hearing.sensing.meaning.presetting.chasing.overdrawing.classifying.charging.parting.polishing.planting.sniffing.fearing.commanding.formulating.bruising.distributing.officiating.seeking.offending.harming.computing.realigning.touring.containing.revising.surprising.helping.pleading.overflowing.reinforcing.nodding.matching.barring.ascertaining.budgeting.allowing.lightening.presetting.deceiving.collecting.slitting.becoming.collecting.cleaning.extending.boiling.overthrowing.obeying.working.painting.dealing.protecting.mugging.flin.ing.updating.referring.skiing.discovering.blinking.spelling.calling.curling.dealing.quitting.shaking.meaning.diverting.smiling.facilitating.satisfying.rolling.siting.asking.holding.blowing.kneeling.assuring.defining.disproving.recruiting.diagnosing.whispering.coughing.lasting.racing.sprouting.acquiring.stitching.heading.soothsaying.parking.splitting.programming.starting.including.knitting.making.jumping.staining.sensing.nominating.regulating.receiving.lasting.boxing.preceding.inventing.increasing.implementing.radiating.relaxing.guarding.brushing.heaping.killing.objecting.confronting.keeping.vexing.accomplishing.orienteering.sinking.repairing.instituting.coughing.preaching.juggling.trading.frying.lightening.scaring.hypothesizing.insuring.sealing.shoeing.grinning.ranking.teaching.coaching.creeping.rising.rubbing.bowing.systemizing.jamming.performing.framing.delaying.quitting.experimenting.smashing.leveling.skipping.sealing.breeding.blinking.beginning.owing.clearing.breaking.growing.guaranteeing.numbering.formulating.standing.verbalizing.executing.shaking.foreseeing.delighting.sneaking.hooking.pasting.objecting.coloring.setting.instructing.generating.measuring.glueing.reconciling.challenging.avoiding.missing.attaining.forecasting.tipping.sharing.bleaching.addressing.proofreading.intending.parting.queueing.crushing.sucking.monitoring.overcoming.copying.restructuring.chewing.casting.tying.ignoring.painting.examining.doubling.doubting.wishing.helping.spiting.wending.thrusting.splitting.muddling.confusing.liking.recognizing.designing.sending.reconciling.inducing.keeping.unifying.excusing.buzzing.joking.forgiving.conserving.budgeting.scratching.initiating.bumping.stamping.suspending.leveling.liking.scribbling.stinking.exhibiting.structuring.rating.queueing.belonging.fearing.broadcasting.hurrying.packing.brushing.glueing.tricking.wandering.bathing.inventorying.expanding.launching.reinforcing.soothing.communicating.predicting.simplifying.pressing.living.exceeding.spotting.disapproving.calculating.spotting.strapping.correcting.rotting.owing.bursting.encouraging.unpacking.cutting.originating.sketching.consisting.causing.affording.impressing.producing.hammering.sensing.scratching.borrowing.transforming.modifying.killing.besetting.lightening.spreading.mediating.sketching.wobbling.staring.adopting.strapping.laying.buying.biding.boasting.possessing.solving.expecting.covering.matching.accepting.rejecting.drying.mattering.blessing.cheering.hugging.wrapping.curing.attempting.meeting.sprin.ing.dressing.using.alighting.speeding.conceiving.meddling.losing.stimulating.clearing.forgetting.rocking.appreciating.rejoicing.increasing.rising.eating.critiquing.depending.spraying.keeping.researching.slapping.requesting.claiming.harassing.betting.crying.mending.irritating.concentrating.summarizing.enforcing.exercising.handwriting.supplying.acquiring.purchasing.lecturing.competing.compiling.beating.binding.bleeding.encouraging.charging.tutoring.kissing.testing.fetching.soothsaying.ending.arriving.sipping.appearing.nominating.praying.arranging.overdrawing.hiding.leaving.entering.maintaining.zooming.investigating.tempting.satisfying.suggesting.flowing.extracting.covering.treating.reigning.handling.bathing.upholding.facilitating.swelling.mending.slipping.paddling.mugging.belonging.pinpointing.wailing.pinching.excusing.occurring.ordering.preparing.assessing.parking.transforming.timing.grating.reflecting.groaning.snowing.shutting.checking.organizing.finding.digging.curving.filling.smoking.folding.releasing.locking.finalizing.installing.radiating.crawling.doing.admiring.telephoning.challenging.contracting.puncturing.deserving.owning.peeling.scorching.dispensing.resolving.plugging.disappearing.hypothesizing.parking.interrupting.exhibiting.rejoicing.reorganizing.bouncing.misunderstanding.choosing.deserving.killing.critiquing.mattering.realizing.swimming.passing.transforming.caring.bowing.professing.pinching.appraising.reminding.publicizing.reaching.leaning.knitting.typing.expecting.delivering.choking.seeing.licking.flapping.clarifying.symbolizing.stealing.trapping.drafting"; + +test "init game" { + const input = "[\"alice\", \"bob\"]"; + var stream = std.json.TokenStream.init(input); + const players = try std.json.parse([]Player, &stream, .{ .allocator = std.testing.allocator }); + defer std.json.parseFree([]Player, players, .{ .allocator = std.testing.allocator }); + + var game = Game.init(std.testing.allocator, players); + defer game.deinit(); + + try std.testing.expectEqualStrings(game.current_judge, "alice"); + try std.testing.expect(game.players.len == 2); + var iter = game.scores.iterator(); + while (iter.next()) |entry| { + try std.testing.expect(entry.value_ptr.* == 0); + } + try std.testing.expect(game.scores.count() == 2); + try std.testing.expect(game.rounds.items.len == 0); +} diff --git a/games/punderplay/src/main.zig b/games/punderplay/src/main.zig new file mode 100644 index 0000000..c17e56f --- /dev/null +++ b/games/punderplay/src/main.zig @@ -0,0 +1,65 @@ +const std = @import("std"); +const extism_pdk = @import("extism-pdk"); +const Plugin = extism_pdk.Plugin; +const json = std.json; + +const game = @import("game.zig"); + +pub fn main() void {} + +const allocator = std.heap.wasm_allocator; + +const GameConfig = struct { + player_ids: []game.Player, +}; + +fn initGame(config: GameConfig, plugin: *Plugin) i32 { + const data = json.stringifyAlloc(allocator, config, .{}) catch unreachable; + plugin.output(data); + return 0; +} + +const LiveEvent = struct { + player_id: []const u8, + event_name: []const u8, + value: EventPayload, +}; + +const EventPayload = struct { + prompt_id: usize, + pun: []const u8, +}; + +fn handleEvent(event: LiveEvent) i32 { + _ = event; + return 0; +} + +const Assigns = struct {}; + +fn renderView(data: Assigns) i32 { + _ = data; + return 0; +} + +export fn init_game() i32 { + var plugin = Plugin.init(allocator); + const input = plugin.getInput() catch unreachable; + defer allocator.free(input); + + var stream = json.TokenStream.init(input); + const config = json.parse(GameConfig, &stream, .{ .allocator = allocator }) catch unreachable; + defer json.parseFree(GameConfig, config, .{ .allocator = allocator }); + + return initGame(config, &plugin); +} + +// export fn handle_event(input: []const u8) i32 { +// const event = json.parse(LiveEventEvent, input, .{}) catch unreachable; +// return handleEvent(event); +// } + +// export fn render(input: []const u8) i32 { +// const assigns = json.parse(Assigns, input, .{}); +// return render(assigns); +// } diff --git a/games/punderplay/zigmod.lock b/games/punderplay/zigmod.lock new file mode 100644 index 0000000..e72e3b8 --- /dev/null +++ b/games/punderplay/zigmod.lock @@ -0,0 +1,2 @@ +2 +git https://github.com/extism/zig-pdk commit-0ee480666df11ad5c3b4fe2cfa47c68da4a7aa73 diff --git a/games/punderplay/zigmod.yml b/games/punderplay/zigmod.yml new file mode 100644 index 0000000..9ba9909 --- /dev/null +++ b/games/punderplay/zigmod.yml @@ -0,0 +1,6 @@ +id: f0fex8nt61gpyoimsjcmtpd4ukxh0f2hbts0zgtjntvclua0 +name: punderplay +license: BSD-3 +description: Pun-based game for GameBox demo +root_dependencies: + - src: git https://github.com/extism/zig-pdk From 3d36b6d1fc8a9d02365778e0c318124270180193 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Fri, 6 Jan 2023 10:44:24 -0700 Subject: [PATCH 2/9] chore: add readme to punderplay for build/testing --- games/punderplay/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 games/punderplay/README.md diff --git a/games/punderplay/README.md b/games/punderplay/README.md new file mode 100644 index 0000000..6ec439c --- /dev/null +++ b/games/punderplay/README.md @@ -0,0 +1,23 @@ +# Punderplay + +### build + +Install [`zigmod`](https://github.com/nektro/zigmod#download) and run: + +```sh +# from the `punderplay` directory +zigmod fetch +zig build +# use ./zig-out/bin/punderplay.wasm +``` + +### Testing + +Run unit tests via `zig test src/game.zig` + +Execute functions in the game: + +```sh +# currently this just echoes out the input after deserializing & reserializing +extism call zig-out/bin/punderplay.wasm init_game --input '{"player_ids": ["steve", "ben"]}' | jq . +``` \ No newline at end of file From 239575e194b776dfe0577938159eafa7e50c26db Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Fri, 6 Jan 2023 10:52:20 -0700 Subject: [PATCH 3/9] test: enable use of single test command for all tests --- games/punderplay/README.md | 2 +- games/punderplay/build.zig | 3 +-- games/punderplay/src/test.zig | 6 ++++++ 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 games/punderplay/src/test.zig diff --git a/games/punderplay/README.md b/games/punderplay/README.md index 6ec439c..478f13b 100644 --- a/games/punderplay/README.md +++ b/games/punderplay/README.md @@ -13,7 +13,7 @@ zig build ### Testing -Run unit tests via `zig test src/game.zig` +Run unit tests via `zig build test` Execute functions in the game: diff --git a/games/punderplay/build.zig b/games/punderplay/build.zig index 64ab473..70e9d15 100644 --- a/games/punderplay/build.zig +++ b/games/punderplay/build.zig @@ -19,8 +19,7 @@ pub fn build(b: *std.build.Builder) void { const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); - const exe_tests = b.addTest("src/main.zig"); - exe_tests.setTarget(target); + const exe_tests = b.addTest("src/test.zig"); exe_tests.setBuildMode(mode); const test_step = b.step("test", "Run unit tests"); diff --git a/games/punderplay/src/test.zig b/games/punderplay/src/test.zig new file mode 100644 index 0000000..efc7bea --- /dev/null +++ b/games/punderplay/src/test.zig @@ -0,0 +1,6 @@ +const test_main = @import("main.zig"); +const test_game = @import("game.zig"); + +test { + @import("std").testing.refAllDecls(@This()); +} From 7be1e69ec39474c8f0bc3072a24b93a042662498 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Fri, 6 Jan 2023 11:05:37 -0700 Subject: [PATCH 4/9] chore: move punderplay ignore paths to own gitignore --- .gitignore | 4 ---- games/punderplay/.gitignore | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 games/punderplay/.gitignore diff --git a/.gitignore b/.gitignore index b64271b..7b351ed 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,3 @@ npm-debug.log dev.secret.exs priv/static/uploads - -games/punderplay/zig-cache/ -games/punderplay/zig-out/ -games/punderplay/.zigmod diff --git a/games/punderplay/.gitignore b/games/punderplay/.gitignore new file mode 100644 index 0000000..58b12f2 --- /dev/null +++ b/games/punderplay/.gitignore @@ -0,0 +1,3 @@ +zig-cache/ +zig-out/ +.zigmod From 92f584adda32021b1231e3585fd39efb40073132 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Sun, 8 Jan 2023 15:27:33 -0700 Subject: [PATCH 5/9] chore: cleanup and update code --- games/punderplay/README.md | 5 ++++- games/punderplay/build.zig | 18 +++++---------- games/punderplay/src/game.zig | 41 +++++++++++++++++++---------------- games/punderplay/src/main.zig | 24 ++++++++------------ games/punderplay/src/test.zig | 6 ----- games/punderplay/zigmod.yml | 1 + 6 files changed, 41 insertions(+), 54 deletions(-) delete mode 100644 games/punderplay/src/test.zig diff --git a/games/punderplay/README.md b/games/punderplay/README.md index 478f13b..a1eb0cd 100644 --- a/games/punderplay/README.md +++ b/games/punderplay/README.md @@ -13,7 +13,10 @@ zig build ### Testing -Run unit tests via `zig build test` +Run unit tests via: +```sh +zig build test-game +``` Execute functions in the game: diff --git a/games/punderplay/build.zig b/games/punderplay/build.zig index 70e9d15..45c768f 100644 --- a/games/punderplay/build.zig +++ b/games/punderplay/build.zig @@ -10,18 +10,10 @@ pub fn build(b: *std.build.Builder) void { deps.addAllTo(exe); exe.install(); - const run_cmd = exe.run(); - run_cmd.step.dependOn(b.getInstallStep()); - if (b.args) |args| { - run_cmd.addArgs(args); - } + const game_tests = b.addTest("src/game.zig"); + deps.addAllTo(game_tests); + game_tests.setBuildMode(mode); - const run_step = b.step("run", "Run the app"); - run_step.dependOn(&run_cmd.step); - - const exe_tests = b.addTest("src/test.zig"); - exe_tests.setBuildMode(mode); - - const test_step = b.step("test", "Run unit tests"); - test_step.dependOn(&exe_tests.step); + const test_step = b.step("test-game", "run `game` tests"); + test_step.dependOn(&game_tests.step); } diff --git a/games/punderplay/src/game.zig b/games/punderplay/src/game.zig index cf00d7f..9c39fc3 100644 --- a/games/punderplay/src/game.zig +++ b/games/punderplay/src/game.zig @@ -3,19 +3,24 @@ const Plugin = @import("extism-pdk").Plugin; pub const Player = []const u8; pub const Judge = Player; -pub const Scores = std.StringHashMap(u8); pub const Round = struct { winner: Player, winning_pun: []const u8, judge: Judge, prompt: [2]u8, }; +pub const Config = struct { + player_ids: []Player, +}; +pub const PlayerScores = struct { + player: Player, + score: u8, +}; -const Game = struct { +pub const Game = struct { allocator: std.mem.Allocator, current_judge: Judge, - players: []Player, - scores: Scores, + players: [2]PlayerScores, rounds: std.ArrayList(Round), const Self = @This(); @@ -23,42 +28,40 @@ const Game = struct { pub fn init(allocator: std.mem.Allocator, players: []Player) Self { // pick a player from the set of current players to act as the judge. // initialize the scores for each player. - var scores = std.StringHashMap(u8).init(allocator); - for (players) |player| { - scores.put(player, 0) catch unreachable; - } + var game_players = [2]PlayerScores{ .{ .player = players[0], .score = 0 }, .{ .player = players[1], .score = 0 } }; return Self{ .allocator = allocator, .current_judge = players[0], - .players = players, - .scores = scores, + .players = game_players, .rounds = std.ArrayList(Round).init(allocator), }; } pub fn deinit(self: *Self) void { - self.scores.deinit(); self.rounds.deinit(); } + + pub fn to_json(self: Self) []const u8 { + return std.json.stringifyAlloc(self.allocator, .{ .current_judge = self.current_judge, .players = self.players, .rounds = self.rounds.items }, .{}) catch unreachable; + } }; const verbs = "watering.cataloging.hunting.wanting.holding.taping.integrating.worrying.loving.spending.fitting.bating.risking.normalizing.restructuring.costing.programming.touching.towing.altering.marketing.yelling.crushing.beholding.agreeing.fencing.sparkling.wiping.sparking.slaying.copying.melting.appraising.complaining.leading.telling.crashing.subtracting.normalizing.grabbing.wrecking.thanking.forming.answering.overhearing.wriggling.rin.ing.admitting.bruising.making.pumping.melting.bumping.dragging.consisting.accepting.dropping.smelling.recognizing.facing.deciding.deserting.riding.ensuring.frightening.shading.flapping.washing.completing.heaping.snoring.draining.clothing.detailing.initiating.dispensing.diagnosing.paddling.sin.ing.promising.handling.planing.separating.thriving.shrinking.scrubbing.confusing.spotting.scattering.noticing.upgrading.piloting.estimating.showing.reigning.folding.contracting.blushing.broadcasting.speaking.slipping.squashing.pecking.hanging.returning.receiving.landing.injecting.fleeing.cheering.sniffing.sleeping.clin.ing.breeding.searching.carving.meaning.attaching.affording.nesting.undergoing.passing.entertaining.longing.enjoying.fighting.wrestling.unfastening.drawing.supposing.knotting.greasing.producing.spinning.squashing.asking.projecting.enduring.adopting.fancying.conducting.conceiving.guessing.mating.overthrowing.regulating.determining.bearing.devising.abiding.piloting.hearing.rhyming.retrieving.servicing.integrating.preaching.rubbing.clarifying.agreeing.striking.wobbling.groaning.speeding.filling.repairing.pining.launching.sneaking.shaping.breathing.spoiling.living.recruiting.proposing.pedaling.wrecking.replacing.operating.trying.licensing.discovering.overdoing.rinsing.camping.displaying.muddling.pricking.nesting.processing.counseling.consolidating.shivering.numbering.removing.sliding.referring.rin.ing.representing.risking.inspecting.assisting.enhancing.administering.identifying.enacting.skipping.shaking.spoiling.spelling.selecting.shopping.causing.reflecting.photographing.withstanding.evaluating.breaking.visiting.creeping.feeding.loading.graduating.combing.tickling.catching.dividing.squealing.breathing.fixing.floating.logging.chewing.carrying.hurting.sacking.expressing.getting.forbidding.sawing.moaning.grinding.ruining.hurrying.balancing.exploding.spilling.welcoming.eliminating.acceding.classifying.smiling.assuring.settling.scheduling.perceiving.moaning.shooting.reconciling.faxing.executing.decaying.marrying.stin.ing.investigating.enacting.caring.questioning.proving.rescuing.filming.shopping.separating.identifying.leading.laying.speeding.tracing.identifying.alerting.sacking.remaining.activating.interesting.boasting.imagining.putting.controlling.disliking.addressing.solving.fleeing.agreeing.shining.fancying.wrin.ing.fading.accelerating.establishing.curling.attacking.guaranteeing.deceiving.patting.applauding.noting.pressing.kneeling.hitting.scheduling.presiding.repeating.prescribing.arising.slaying.adding.fitting.snoring.shaking.sewing.inspecting.educating.manipulating.belonging.giving.participating.agreeing.doubting.misunderstanding.following.trotting.writing.clin.ing.interesting.damming.correlating.plugging.attending.retiring.beholding.understanding.walking.pinpointing.photographing.braking.soaking.folding.remembering.slin.ing.borrowing.rocking.allowing.filming.obeying.coiling.cycling.untidying.shrinking.preferring.stirring.fixing.attending.baking.saying.rotting.learning.governing.confessing.reminding.utilizing.bruising.dramatizing.knowing.puncturing.shearing.suggesting.achieving.heading.sliding.punching.greeting.gazing.swin.ing.spending.occurring.sneezing.creating.sparking.hiding.stitching.promoting.changing.snowing.taking.lying.reading.responding.bouncing.baking.pecking.multiplying.conserving.challenging.losing.sowing.fooling.marketing.informing.spilling.matching.speaking.dealing.detecting.rating.screwing.bruising.interlaying.phoning.ensuring.binding.stoping.scattering.weighing.participating.editing.letting.publicizing.preparing.financing.shearing.checking.writing.exciting.firing.bombing.disliking.restoring.eating.fighting.answering.balancing.sending.blotting.amusing.disagreeing.innovating.relying.correcting.confronting.judging.reducing.entertaining.arguing.selecting.stamping.parking.naming.noticing.doing.chopping.banging.engineering.trusting.describing.delegating.cheating.lending.mistaking.squeaking.winding.comparing.adapting.cracking.correlating.scolding.blushing.scraping.buzzing.existing.improvising.praising.splitting.distributing.curing.overdoing.mapping.progressing.activating.feeding.forgiving.dressing.manning.polishing.smoking.reconciling.knowing.tugging.being.causing.shutting.preventing.disappearing.presenting.banging.explaining.crossing.predicting.converting.sighing.designing.fooling.bursting.decorating.battling.hearing.sensing.meaning.presetting.chasing.overdrawing.classifying.charging.parting.polishing.planting.sniffing.fearing.commanding.formulating.bruising.distributing.officiating.seeking.offending.harming.computing.realigning.touring.containing.revising.surprising.helping.pleading.overflowing.reinforcing.nodding.matching.barring.ascertaining.budgeting.allowing.lightening.presetting.deceiving.collecting.slitting.becoming.collecting.cleaning.extending.boiling.overthrowing.obeying.working.painting.dealing.protecting.mugging.flin.ing.updating.referring.skiing.discovering.blinking.spelling.calling.curling.dealing.quitting.shaking.meaning.diverting.smiling.facilitating.satisfying.rolling.siting.asking.holding.blowing.kneeling.assuring.defining.disproving.recruiting.diagnosing.whispering.coughing.lasting.racing.sprouting.acquiring.stitching.heading.soothsaying.parking.splitting.programming.starting.including.knitting.making.jumping.staining.sensing.nominating.regulating.receiving.lasting.boxing.preceding.inventing.increasing.implementing.radiating.relaxing.guarding.brushing.heaping.killing.objecting.confronting.keeping.vexing.accomplishing.orienteering.sinking.repairing.instituting.coughing.preaching.juggling.trading.frying.lightening.scaring.hypothesizing.insuring.sealing.shoeing.grinning.ranking.teaching.coaching.creeping.rising.rubbing.bowing.systemizing.jamming.performing.framing.delaying.quitting.experimenting.smashing.leveling.skipping.sealing.breeding.blinking.beginning.owing.clearing.breaking.growing.guaranteeing.numbering.formulating.standing.verbalizing.executing.shaking.foreseeing.delighting.sneaking.hooking.pasting.objecting.coloring.setting.instructing.generating.measuring.glueing.reconciling.challenging.avoiding.missing.attaining.forecasting.tipping.sharing.bleaching.addressing.proofreading.intending.parting.queueing.crushing.sucking.monitoring.overcoming.copying.restructuring.chewing.casting.tying.ignoring.painting.examining.doubling.doubting.wishing.helping.spiting.wending.thrusting.splitting.muddling.confusing.liking.recognizing.designing.sending.reconciling.inducing.keeping.unifying.excusing.buzzing.joking.forgiving.conserving.budgeting.scratching.initiating.bumping.stamping.suspending.leveling.liking.scribbling.stinking.exhibiting.structuring.rating.queueing.belonging.fearing.broadcasting.hurrying.packing.brushing.glueing.tricking.wandering.bathing.inventorying.expanding.launching.reinforcing.soothing.communicating.predicting.simplifying.pressing.living.exceeding.spotting.disapproving.calculating.spotting.strapping.correcting.rotting.owing.bursting.encouraging.unpacking.cutting.originating.sketching.consisting.causing.affording.impressing.producing.hammering.sensing.scratching.borrowing.transforming.modifying.killing.besetting.lightening.spreading.mediating.sketching.wobbling.staring.adopting.strapping.laying.buying.biding.boasting.possessing.solving.expecting.covering.matching.accepting.rejecting.drying.mattering.blessing.cheering.hugging.wrapping.curing.attempting.meeting.sprin.ing.dressing.using.alighting.speeding.conceiving.meddling.losing.stimulating.clearing.forgetting.rocking.appreciating.rejoicing.increasing.rising.eating.critiquing.depending.spraying.keeping.researching.slapping.requesting.claiming.harassing.betting.crying.mending.irritating.concentrating.summarizing.enforcing.exercising.handwriting.supplying.acquiring.purchasing.lecturing.competing.compiling.beating.binding.bleeding.encouraging.charging.tutoring.kissing.testing.fetching.soothsaying.ending.arriving.sipping.appearing.nominating.praying.arranging.overdrawing.hiding.leaving.entering.maintaining.zooming.investigating.tempting.satisfying.suggesting.flowing.extracting.covering.treating.reigning.handling.bathing.upholding.facilitating.swelling.mending.slipping.paddling.mugging.belonging.pinpointing.wailing.pinching.excusing.occurring.ordering.preparing.assessing.parking.transforming.timing.grating.reflecting.groaning.snowing.shutting.checking.organizing.finding.digging.curving.filling.smoking.folding.releasing.locking.finalizing.installing.radiating.crawling.doing.admiring.telephoning.challenging.contracting.puncturing.deserving.owning.peeling.scorching.dispensing.resolving.plugging.disappearing.hypothesizing.parking.interrupting.exhibiting.rejoicing.reorganizing.bouncing.misunderstanding.choosing.deserving.killing.critiquing.mattering.realizing.swimming.passing.transforming.caring.bowing.professing.pinching.appraising.reminding.publicizing.reaching.leaning.knitting.typing.expecting.delivering.choking.seeing.licking.flapping.clarifying.symbolizing.stealing.trapping.drafting"; test "init game" { + const ta = std.testing.allocator; const input = "[\"alice\", \"bob\"]"; var stream = std.json.TokenStream.init(input); - const players = try std.json.parse([]Player, &stream, .{ .allocator = std.testing.allocator }); - defer std.json.parseFree([]Player, players, .{ .allocator = std.testing.allocator }); + const players = try std.json.parse([]Player, &stream, .{ .allocator = ta }); + defer std.json.parseFree([]Player, players, .{ .allocator = ta }); - var game = Game.init(std.testing.allocator, players); + var game = Game.init(ta, players); defer game.deinit(); try std.testing.expectEqualStrings(game.current_judge, "alice"); try std.testing.expect(game.players.len == 2); - var iter = game.scores.iterator(); - while (iter.next()) |entry| { - try std.testing.expect(entry.value_ptr.* == 0); - } - try std.testing.expect(game.scores.count() == 2); try std.testing.expect(game.rounds.items.len == 0); + for (game.players) |player| { + try std.testing.expect(player.score == 0); + } } diff --git a/games/punderplay/src/main.zig b/games/punderplay/src/main.zig index c17e56f..f70fd5e 100644 --- a/games/punderplay/src/main.zig +++ b/games/punderplay/src/main.zig @@ -2,19 +2,13 @@ const std = @import("std"); const extism_pdk = @import("extism-pdk"); const Plugin = extism_pdk.Plugin; const json = std.json; - const game = @import("game.zig"); pub fn main() void {} -const allocator = std.heap.wasm_allocator; - -const GameConfig = struct { - player_ids: []game.Player, -}; - -fn initGame(config: GameConfig, plugin: *Plugin) i32 { - const data = json.stringifyAlloc(allocator, config, .{}) catch unreachable; +pub fn initGame(config: game.Config, plugin: *Plugin) i32 { + const game_state = game.Game.init(plugin.allocator, config.player_ids); + const data = game_state.to_json(); plugin.output(data); return 0; } @@ -30,26 +24,26 @@ const EventPayload = struct { pun: []const u8, }; -fn handleEvent(event: LiveEvent) i32 { +pub fn handleEvent(event: LiveEvent) i32 { _ = event; return 0; } const Assigns = struct {}; -fn renderView(data: Assigns) i32 { +pub fn renderView(data: Assigns) i32 { _ = data; return 0; } export fn init_game() i32 { - var plugin = Plugin.init(allocator); + var plugin = Plugin.init(std.heap.wasm_allocator); const input = plugin.getInput() catch unreachable; - defer allocator.free(input); + defer plugin.allocator.free(input); var stream = json.TokenStream.init(input); - const config = json.parse(GameConfig, &stream, .{ .allocator = allocator }) catch unreachable; - defer json.parseFree(GameConfig, config, .{ .allocator = allocator }); + const config = json.parse(game.Config, &stream, .{ .allocator = plugin.allocator }) catch unreachable; + defer json.parseFree(game.Config, config, .{ .allocator = plugin.allocator }); return initGame(config, &plugin); } diff --git a/games/punderplay/src/test.zig b/games/punderplay/src/test.zig deleted file mode 100644 index efc7bea..0000000 --- a/games/punderplay/src/test.zig +++ /dev/null @@ -1,6 +0,0 @@ -const test_main = @import("main.zig"); -const test_game = @import("game.zig"); - -test { - @import("std").testing.refAllDecls(@This()); -} diff --git a/games/punderplay/zigmod.yml b/games/punderplay/zigmod.yml index 9ba9909..37fceb8 100644 --- a/games/punderplay/zigmod.yml +++ b/games/punderplay/zigmod.yml @@ -4,3 +4,4 @@ license: BSD-3 description: Pun-based game for GameBox demo root_dependencies: - src: git https://github.com/extism/zig-pdk + \ No newline at end of file From 861c3c5133326248420ee81a106dca765a60b1a0 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Mon, 9 Jan 2023 23:37:42 -0700 Subject: [PATCH 6/9] feat: add polymorphic store with mock tests --- games/punderplay/README.md | 1 + games/punderplay/build.zig | 11 +++- games/punderplay/src/game.zig | 27 ++++++++- games/punderplay/src/main.zig | 47 +++++++++++---- games/punderplay/src/store.zig | 105 +++++++++++++++++++++++++++++++++ 5 files changed, 172 insertions(+), 19 deletions(-) create mode 100644 games/punderplay/src/store.zig diff --git a/games/punderplay/README.md b/games/punderplay/README.md index a1eb0cd..4ba78b5 100644 --- a/games/punderplay/README.md +++ b/games/punderplay/README.md @@ -16,6 +16,7 @@ zig build Run unit tests via: ```sh zig build test-game +zig build test-store ``` Execute functions in the game: diff --git a/games/punderplay/build.zig b/games/punderplay/build.zig index 45c768f..9fdcbc4 100644 --- a/games/punderplay/build.zig +++ b/games/punderplay/build.zig @@ -12,8 +12,13 @@ pub fn build(b: *std.build.Builder) void { const game_tests = b.addTest("src/game.zig"); deps.addAllTo(game_tests); - game_tests.setBuildMode(mode); - const test_step = b.step("test-game", "run `game` tests"); - test_step.dependOn(&game_tests.step); + const store_tests = b.addTest("src/store.zig"); + deps.addAllTo(store_tests); + + const game_test_step = b.step("test-game", "run `game` tests"); + game_test_step.dependOn(&game_tests.step); + + const store_test_step = b.step("test-store", "run `store` tests"); + store_test_step.dependOn(&store_tests.step); } diff --git a/games/punderplay/src/game.zig b/games/punderplay/src/game.zig index 9c39fc3..1697557 100644 --- a/games/punderplay/src/game.zig +++ b/games/punderplay/src/game.zig @@ -17,10 +17,16 @@ pub const PlayerScores = struct { score: u8, }; +pub const GameData = struct { + current_judge: Judge, + players: []PlayerScores, + rounds: []Round, +}; + pub const Game = struct { allocator: std.mem.Allocator, current_judge: Judge, - players: [2]PlayerScores, + players: []PlayerScores, rounds: std.ArrayList(Round), const Self = @This(); @@ -28,11 +34,11 @@ pub const Game = struct { pub fn init(allocator: std.mem.Allocator, players: []Player) Self { // pick a player from the set of current players to act as the judge. // initialize the scores for each player. - var game_players = [2]PlayerScores{ .{ .player = players[0], .score = 0 }, .{ .player = players[1], .score = 0 } }; + var game_players = [_]PlayerScores{ .{ .player = players[0], .score = 0 }, .{ .player = players[1], .score = 0 } }; return Self{ .allocator = allocator, .current_judge = players[0], - .players = game_players, + .players = &game_players, .rounds = std.ArrayList(Round).init(allocator), }; } @@ -44,6 +50,21 @@ pub const Game = struct { pub fn to_json(self: Self) []const u8 { return std.json.stringifyAlloc(self.allocator, .{ .current_judge = self.current_judge, .players = self.players, .rounds = self.rounds.items }, .{}) catch unreachable; } + + pub fn from_json(allocator: std.mem.Allocator, data: []const u8) Self { + var stream = std.json.TokenStream.init(data); + const gameData = std.json.parse(GameData, &stream, .{ .allocator = allocator }) catch unreachable; + defer std.json.parseFree(GameData, gameData, .{ .allocator = allocator }); + + var rounds = std.ArrayList(Round).init(allocator); + rounds.appendSlice(gameData.rounds) catch unreachable; + return Self{ + .allocator = allocator, + .current_judge = gameData.current_judge, + .players = gameData.players, + .rounds = rounds, + }; + } }; const verbs = "watering.cataloging.hunting.wanting.holding.taping.integrating.worrying.loving.spending.fitting.bating.risking.normalizing.restructuring.costing.programming.touching.towing.altering.marketing.yelling.crushing.beholding.agreeing.fencing.sparkling.wiping.sparking.slaying.copying.melting.appraising.complaining.leading.telling.crashing.subtracting.normalizing.grabbing.wrecking.thanking.forming.answering.overhearing.wriggling.rin.ing.admitting.bruising.making.pumping.melting.bumping.dragging.consisting.accepting.dropping.smelling.recognizing.facing.deciding.deserting.riding.ensuring.frightening.shading.flapping.washing.completing.heaping.snoring.draining.clothing.detailing.initiating.dispensing.diagnosing.paddling.sin.ing.promising.handling.planing.separating.thriving.shrinking.scrubbing.confusing.spotting.scattering.noticing.upgrading.piloting.estimating.showing.reigning.folding.contracting.blushing.broadcasting.speaking.slipping.squashing.pecking.hanging.returning.receiving.landing.injecting.fleeing.cheering.sniffing.sleeping.clin.ing.breeding.searching.carving.meaning.attaching.affording.nesting.undergoing.passing.entertaining.longing.enjoying.fighting.wrestling.unfastening.drawing.supposing.knotting.greasing.producing.spinning.squashing.asking.projecting.enduring.adopting.fancying.conducting.conceiving.guessing.mating.overthrowing.regulating.determining.bearing.devising.abiding.piloting.hearing.rhyming.retrieving.servicing.integrating.preaching.rubbing.clarifying.agreeing.striking.wobbling.groaning.speeding.filling.repairing.pining.launching.sneaking.shaping.breathing.spoiling.living.recruiting.proposing.pedaling.wrecking.replacing.operating.trying.licensing.discovering.overdoing.rinsing.camping.displaying.muddling.pricking.nesting.processing.counseling.consolidating.shivering.numbering.removing.sliding.referring.rin.ing.representing.risking.inspecting.assisting.enhancing.administering.identifying.enacting.skipping.shaking.spoiling.spelling.selecting.shopping.causing.reflecting.photographing.withstanding.evaluating.breaking.visiting.creeping.feeding.loading.graduating.combing.tickling.catching.dividing.squealing.breathing.fixing.floating.logging.chewing.carrying.hurting.sacking.expressing.getting.forbidding.sawing.moaning.grinding.ruining.hurrying.balancing.exploding.spilling.welcoming.eliminating.acceding.classifying.smiling.assuring.settling.scheduling.perceiving.moaning.shooting.reconciling.faxing.executing.decaying.marrying.stin.ing.investigating.enacting.caring.questioning.proving.rescuing.filming.shopping.separating.identifying.leading.laying.speeding.tracing.identifying.alerting.sacking.remaining.activating.interesting.boasting.imagining.putting.controlling.disliking.addressing.solving.fleeing.agreeing.shining.fancying.wrin.ing.fading.accelerating.establishing.curling.attacking.guaranteeing.deceiving.patting.applauding.noting.pressing.kneeling.hitting.scheduling.presiding.repeating.prescribing.arising.slaying.adding.fitting.snoring.shaking.sewing.inspecting.educating.manipulating.belonging.giving.participating.agreeing.doubting.misunderstanding.following.trotting.writing.clin.ing.interesting.damming.correlating.plugging.attending.retiring.beholding.understanding.walking.pinpointing.photographing.braking.soaking.folding.remembering.slin.ing.borrowing.rocking.allowing.filming.obeying.coiling.cycling.untidying.shrinking.preferring.stirring.fixing.attending.baking.saying.rotting.learning.governing.confessing.reminding.utilizing.bruising.dramatizing.knowing.puncturing.shearing.suggesting.achieving.heading.sliding.punching.greeting.gazing.swin.ing.spending.occurring.sneezing.creating.sparking.hiding.stitching.promoting.changing.snowing.taking.lying.reading.responding.bouncing.baking.pecking.multiplying.conserving.challenging.losing.sowing.fooling.marketing.informing.spilling.matching.speaking.dealing.detecting.rating.screwing.bruising.interlaying.phoning.ensuring.binding.stoping.scattering.weighing.participating.editing.letting.publicizing.preparing.financing.shearing.checking.writing.exciting.firing.bombing.disliking.restoring.eating.fighting.answering.balancing.sending.blotting.amusing.disagreeing.innovating.relying.correcting.confronting.judging.reducing.entertaining.arguing.selecting.stamping.parking.naming.noticing.doing.chopping.banging.engineering.trusting.describing.delegating.cheating.lending.mistaking.squeaking.winding.comparing.adapting.cracking.correlating.scolding.blushing.scraping.buzzing.existing.improvising.praising.splitting.distributing.curing.overdoing.mapping.progressing.activating.feeding.forgiving.dressing.manning.polishing.smoking.reconciling.knowing.tugging.being.causing.shutting.preventing.disappearing.presenting.banging.explaining.crossing.predicting.converting.sighing.designing.fooling.bursting.decorating.battling.hearing.sensing.meaning.presetting.chasing.overdrawing.classifying.charging.parting.polishing.planting.sniffing.fearing.commanding.formulating.bruising.distributing.officiating.seeking.offending.harming.computing.realigning.touring.containing.revising.surprising.helping.pleading.overflowing.reinforcing.nodding.matching.barring.ascertaining.budgeting.allowing.lightening.presetting.deceiving.collecting.slitting.becoming.collecting.cleaning.extending.boiling.overthrowing.obeying.working.painting.dealing.protecting.mugging.flin.ing.updating.referring.skiing.discovering.blinking.spelling.calling.curling.dealing.quitting.shaking.meaning.diverting.smiling.facilitating.satisfying.rolling.siting.asking.holding.blowing.kneeling.assuring.defining.disproving.recruiting.diagnosing.whispering.coughing.lasting.racing.sprouting.acquiring.stitching.heading.soothsaying.parking.splitting.programming.starting.including.knitting.making.jumping.staining.sensing.nominating.regulating.receiving.lasting.boxing.preceding.inventing.increasing.implementing.radiating.relaxing.guarding.brushing.heaping.killing.objecting.confronting.keeping.vexing.accomplishing.orienteering.sinking.repairing.instituting.coughing.preaching.juggling.trading.frying.lightening.scaring.hypothesizing.insuring.sealing.shoeing.grinning.ranking.teaching.coaching.creeping.rising.rubbing.bowing.systemizing.jamming.performing.framing.delaying.quitting.experimenting.smashing.leveling.skipping.sealing.breeding.blinking.beginning.owing.clearing.breaking.growing.guaranteeing.numbering.formulating.standing.verbalizing.executing.shaking.foreseeing.delighting.sneaking.hooking.pasting.objecting.coloring.setting.instructing.generating.measuring.glueing.reconciling.challenging.avoiding.missing.attaining.forecasting.tipping.sharing.bleaching.addressing.proofreading.intending.parting.queueing.crushing.sucking.monitoring.overcoming.copying.restructuring.chewing.casting.tying.ignoring.painting.examining.doubling.doubting.wishing.helping.spiting.wending.thrusting.splitting.muddling.confusing.liking.recognizing.designing.sending.reconciling.inducing.keeping.unifying.excusing.buzzing.joking.forgiving.conserving.budgeting.scratching.initiating.bumping.stamping.suspending.leveling.liking.scribbling.stinking.exhibiting.structuring.rating.queueing.belonging.fearing.broadcasting.hurrying.packing.brushing.glueing.tricking.wandering.bathing.inventorying.expanding.launching.reinforcing.soothing.communicating.predicting.simplifying.pressing.living.exceeding.spotting.disapproving.calculating.spotting.strapping.correcting.rotting.owing.bursting.encouraging.unpacking.cutting.originating.sketching.consisting.causing.affording.impressing.producing.hammering.sensing.scratching.borrowing.transforming.modifying.killing.besetting.lightening.spreading.mediating.sketching.wobbling.staring.adopting.strapping.laying.buying.biding.boasting.possessing.solving.expecting.covering.matching.accepting.rejecting.drying.mattering.blessing.cheering.hugging.wrapping.curing.attempting.meeting.sprin.ing.dressing.using.alighting.speeding.conceiving.meddling.losing.stimulating.clearing.forgetting.rocking.appreciating.rejoicing.increasing.rising.eating.critiquing.depending.spraying.keeping.researching.slapping.requesting.claiming.harassing.betting.crying.mending.irritating.concentrating.summarizing.enforcing.exercising.handwriting.supplying.acquiring.purchasing.lecturing.competing.compiling.beating.binding.bleeding.encouraging.charging.tutoring.kissing.testing.fetching.soothsaying.ending.arriving.sipping.appearing.nominating.praying.arranging.overdrawing.hiding.leaving.entering.maintaining.zooming.investigating.tempting.satisfying.suggesting.flowing.extracting.covering.treating.reigning.handling.bathing.upholding.facilitating.swelling.mending.slipping.paddling.mugging.belonging.pinpointing.wailing.pinching.excusing.occurring.ordering.preparing.assessing.parking.transforming.timing.grating.reflecting.groaning.snowing.shutting.checking.organizing.finding.digging.curving.filling.smoking.folding.releasing.locking.finalizing.installing.radiating.crawling.doing.admiring.telephoning.challenging.contracting.puncturing.deserving.owning.peeling.scorching.dispensing.resolving.plugging.disappearing.hypothesizing.parking.interrupting.exhibiting.rejoicing.reorganizing.bouncing.misunderstanding.choosing.deserving.killing.critiquing.mattering.realizing.swimming.passing.transforming.caring.bowing.professing.pinching.appraising.reminding.publicizing.reaching.leaning.knitting.typing.expecting.delivering.choking.seeing.licking.flapping.clarifying.symbolizing.stealing.trapping.drafting"; diff --git a/games/punderplay/src/main.zig b/games/punderplay/src/main.zig index f70fd5e..9604875 100644 --- a/games/punderplay/src/main.zig +++ b/games/punderplay/src/main.zig @@ -4,13 +4,12 @@ const Plugin = extism_pdk.Plugin; const json = std.json; const game = @import("game.zig"); +const VAR_STATE = "state"; + pub fn main() void {} -pub fn initGame(config: game.Config, plugin: *Plugin) i32 { - const game_state = game.Game.init(plugin.allocator, config.player_ids); - const data = game_state.to_json(); - plugin.output(data); - return 0; +pub fn initGame(config: game.Config, allocator: std.mem.Allocator) game.Game { + return game.Game.init(allocator, config.player_ids); } const LiveEvent = struct { @@ -24,9 +23,11 @@ const EventPayload = struct { pun: []const u8, }; -pub fn handleEvent(event: LiveEvent) i32 { +pub fn handleEvent(event: LiveEvent, state: *game.Game) *game.Game { + // switch (event.event_name) {} _ = event; - return 0; + + return state; } const Assigns = struct {}; @@ -45,15 +46,35 @@ export fn init_game() i32 { const config = json.parse(game.Config, &stream, .{ .allocator = plugin.allocator }) catch unreachable; defer json.parseFree(game.Config, config, .{ .allocator = plugin.allocator }); - return initGame(config, &plugin); + var gameState = initGame(config, plugin.allocator); + defer gameState.deinit(); + + plugin.setVar(VAR_STATE, gameState.to_json()); + + return 0; } -// export fn handle_event(input: []const u8) i32 { -// const event = json.parse(LiveEventEvent, input, .{}) catch unreachable; -// return handleEvent(event); -// } +export fn handle_event() i32 { + var plugin = Plugin.init(std.heap.wasm_allocator); + const input = plugin.getInput() catch unreachable; + defer plugin.allocator.free(input); + + var stream = json.TokenStream.init(input); + const event = json.parse(LiveEvent, &stream, .{ .allocator = plugin.allocator }) catch unreachable; + defer json.parseFree(LiveEvent, event, .{ .allocator = plugin.allocator }); + + var gameState = game.Game.from_json(plugin.allocator, plugin.getVar(VAR_STATE) catch unreachable orelse "{}"); + defer gameState.deinit(); + + var newGameState = handleEvent(event, &gameState); + defer newGameState.deinit(); + + plugin.setVar(VAR_STATE, newGameState.*.to_json()); + + return 0; +} // export fn render(input: []const u8) i32 { // const assigns = json.parse(Assigns, input, .{}); -// return render(assigns); +// return renderView(assigns); // } diff --git a/games/punderplay/src/store.zig b/games/punderplay/src/store.zig new file mode 100644 index 0000000..e29f828 --- /dev/null +++ b/games/punderplay/src/store.zig @@ -0,0 +1,105 @@ +const std = @import("std"); +const extism_pdk = @import("extism-pdk"); +const Plugin = extism_pdk.Plugin; +const json = std.json; +const game = @import("game.zig"); + +pub const PluginStore = struct { + inner: *Plugin, + + const Self = @This(); + + pub fn get(self: Self, key: []const u8) []const u8 { + return self.inner.getVar(key) catch unreachable orelse ""; + } + + pub fn set(self: Self, key: []const u8, value: []const u8) void { + self.inner.setVar(key, value); + } +}; + +pub const MockStore = struct { + inner: std.StringHashMap([]const u8), + + const Self = @This(); + + pub fn init(allocator: std.mem.Allocator) Self { + return Self{ + .inner = std.StringHashMap([]const u8).init(allocator), + }; + } + + pub fn deinit(self: *Self) void { + self.inner.deinit(); + } + + pub fn get(self: Self, key: []const u8) []const u8 { + return self.inner.get(key) orelse ""; + } + + pub fn set(self: *Self, key: []const u8, value: []const u8) void { + self.inner.put(key, value) catch unreachable; + } +}; + +// Thank you to Yigong Liu, and their post[0], without which I'd not have figured this out... +// 0: https://zig.news/yglcode/code-study-interface-idiomspatterns-in-zig-standard-libraries-4lkj +pub const Store = struct { + ptr: *anyopaque, + vtab: *const VTab, + const VTab = struct { + get: *const fn (ptr: *anyopaque, key: []const u8) []const u8, + set: *const fn (ptr: *anyopaque, key: []const u8, value: []const u8) void, + }; + + pub fn get(self: Store, key: []const u8) []const u8 { + return self.vtab.get(self.ptr, key); + } + + pub fn set(self: Store, key: []const u8, value: []const u8) void { + self.vtab.set(self.ptr, key, value); + } + + pub fn init(store: anytype) Store { + const Ptr = @TypeOf(store); + const PtrInfo = @typeInfo(Ptr); + std.debug.assert(PtrInfo == .Pointer); + std.debug.assert(PtrInfo.Pointer.size == .One); + std.debug.assert(@typeInfo(PtrInfo.Pointer.child) == .Struct); + + const alignment = PtrInfo.Pointer.alignment; + const impl = struct { + fn get(ptr: *anyopaque, key: []const u8) []const u8 { + const self = @ptrCast(Ptr, @alignCast(alignment, ptr)); + return self.get(key); + } + + fn set(ptr: *anyopaque, key: []const u8, value: []const u8) void { + const self = @ptrCast(Ptr, @alignCast(alignment, ptr)); + self.set(key, value); + } + }; + + return .{ .ptr = store, .vtab = &.{ + .get = impl.get, + .set = impl.set, + } }; + } +}; + +test "mock store" { + var mock = MockStore.init(std.testing.allocator); + defer mock.deinit(); + + mock.set("some_key", "some_value"); + try std.testing.expectEqualStrings("some_value", mock.get("some_key")); +} + +test "Store with MockStore" { + var m = MockStore.init(std.testing.allocator); + defer m.deinit(); + + var store = Store.init(&m); + store.set("some_key", "some_value"); + try std.testing.expectEqualStrings("some_value", store.get("some_key")); +} From e9fb50c89e58bb46ea1bb194939d7747fdc01bfc Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Wed, 11 Jan 2023 21:21:45 -0700 Subject: [PATCH 7/9] feat: working store, game leaks memory still --- games/punderplay/src/game.zig | 94 +++++++++++++++++++--------------- games/punderplay/src/main.zig | 38 +++++++------- games/punderplay/src/store.zig | 4 ++ games/punderplay/zigmod.yml | 1 - 4 files changed, 76 insertions(+), 61 deletions(-) diff --git a/games/punderplay/src/game.zig b/games/punderplay/src/game.zig index 1697557..894a7d8 100644 --- a/games/punderplay/src/game.zig +++ b/games/punderplay/src/game.zig @@ -2,87 +2,97 @@ const std = @import("std"); const Plugin = @import("extism-pdk").Plugin; pub const Player = []const u8; + pub const Judge = Player; + pub const Round = struct { winner: Player, winning_pun: []const u8, judge: Judge, - prompt: [2]u8, + prompt: [2][]const u8, }; + pub const Config = struct { player_ids: []Player, }; -pub const PlayerScores = struct { + +pub const PlayerScore = struct { player: Player, score: u8, }; -pub const GameData = struct { - current_judge: Judge, - players: []PlayerScores, - rounds: []Round, -}; - pub const Game = struct { - allocator: std.mem.Allocator, current_judge: Judge, - players: []PlayerScores, - rounds: std.ArrayList(Round), + players: []PlayerScore, + rounds: []Round, + version: u32, const Self = @This(); - pub fn init(allocator: std.mem.Allocator, players: []Player) Self { + pub fn init(self: *Game, allocator: std.mem.Allocator, players: []Player) !void { + defer allocator.free(players); // pick a player from the set of current players to act as the judge. // initialize the scores for each player. - var game_players = [_]PlayerScores{ .{ .player = players[0], .score = 0 }, .{ .player = players[1], .score = 0 } }; - return Self{ - .allocator = allocator, - .current_judge = players[0], - .players = &game_players, - .rounds = std.ArrayList(Round).init(allocator), - }; - } + self.players = try allocator.alloc(PlayerScore, players.len); + for (players) |player, i| { + self.players[i] = PlayerScore{ .player = player, .score = 0 }; + } - pub fn deinit(self: *Self) void { - self.rounds.deinit(); + self.current_judge = players[0]; + self.rounds = &[_]Round{}; + self.version = 0; } - pub fn to_json(self: Self) []const u8 { - return std.json.stringifyAlloc(self.allocator, .{ .current_judge = self.current_judge, .players = self.players, .rounds = self.rounds.items }, .{}) catch unreachable; + // pub fn deinit(self: *Game, allocator: std.mem.Allocator) void { + // allocator.free(self.players); + // } + + pub fn toJson(self: Self, allocator: std.mem.Allocator) ![]const u8 { + return std.json.stringifyAlloc(allocator, self, .{}); } - pub fn from_json(allocator: std.mem.Allocator, data: []const u8) Self { + pub fn fromJson(self: *Game, allocator: std.mem.Allocator, data: []const u8) !void { var stream = std.json.TokenStream.init(data); - const gameData = std.json.parse(GameData, &stream, .{ .allocator = allocator }) catch unreachable; - defer std.json.parseFree(GameData, gameData, .{ .allocator = allocator }); - - var rounds = std.ArrayList(Round).init(allocator); - rounds.appendSlice(gameData.rounds) catch unreachable; - return Self{ - .allocator = allocator, - .current_judge = gameData.current_judge, - .players = gameData.players, - .rounds = rounds, - }; + const game = try std.json.parse(Game, &stream, .{ .allocator = allocator }); + defer std.json.parseFree(Game, game, .{ .allocator = allocator }); + + self.current_judge = game.current_judge; + self.players = game.players; + self.rounds = game.rounds; + self.version = game.version; + } + + pub fn inc_version(self: *Self) void { + self.version += 1; } }; const verbs = "watering.cataloging.hunting.wanting.holding.taping.integrating.worrying.loving.spending.fitting.bating.risking.normalizing.restructuring.costing.programming.touching.towing.altering.marketing.yelling.crushing.beholding.agreeing.fencing.sparkling.wiping.sparking.slaying.copying.melting.appraising.complaining.leading.telling.crashing.subtracting.normalizing.grabbing.wrecking.thanking.forming.answering.overhearing.wriggling.rin.ing.admitting.bruising.making.pumping.melting.bumping.dragging.consisting.accepting.dropping.smelling.recognizing.facing.deciding.deserting.riding.ensuring.frightening.shading.flapping.washing.completing.heaping.snoring.draining.clothing.detailing.initiating.dispensing.diagnosing.paddling.sin.ing.promising.handling.planing.separating.thriving.shrinking.scrubbing.confusing.spotting.scattering.noticing.upgrading.piloting.estimating.showing.reigning.folding.contracting.blushing.broadcasting.speaking.slipping.squashing.pecking.hanging.returning.receiving.landing.injecting.fleeing.cheering.sniffing.sleeping.clin.ing.breeding.searching.carving.meaning.attaching.affording.nesting.undergoing.passing.entertaining.longing.enjoying.fighting.wrestling.unfastening.drawing.supposing.knotting.greasing.producing.spinning.squashing.asking.projecting.enduring.adopting.fancying.conducting.conceiving.guessing.mating.overthrowing.regulating.determining.bearing.devising.abiding.piloting.hearing.rhyming.retrieving.servicing.integrating.preaching.rubbing.clarifying.agreeing.striking.wobbling.groaning.speeding.filling.repairing.pining.launching.sneaking.shaping.breathing.spoiling.living.recruiting.proposing.pedaling.wrecking.replacing.operating.trying.licensing.discovering.overdoing.rinsing.camping.displaying.muddling.pricking.nesting.processing.counseling.consolidating.shivering.numbering.removing.sliding.referring.rin.ing.representing.risking.inspecting.assisting.enhancing.administering.identifying.enacting.skipping.shaking.spoiling.spelling.selecting.shopping.causing.reflecting.photographing.withstanding.evaluating.breaking.visiting.creeping.feeding.loading.graduating.combing.tickling.catching.dividing.squealing.breathing.fixing.floating.logging.chewing.carrying.hurting.sacking.expressing.getting.forbidding.sawing.moaning.grinding.ruining.hurrying.balancing.exploding.spilling.welcoming.eliminating.acceding.classifying.smiling.assuring.settling.scheduling.perceiving.moaning.shooting.reconciling.faxing.executing.decaying.marrying.stin.ing.investigating.enacting.caring.questioning.proving.rescuing.filming.shopping.separating.identifying.leading.laying.speeding.tracing.identifying.alerting.sacking.remaining.activating.interesting.boasting.imagining.putting.controlling.disliking.addressing.solving.fleeing.agreeing.shining.fancying.wrin.ing.fading.accelerating.establishing.curling.attacking.guaranteeing.deceiving.patting.applauding.noting.pressing.kneeling.hitting.scheduling.presiding.repeating.prescribing.arising.slaying.adding.fitting.snoring.shaking.sewing.inspecting.educating.manipulating.belonging.giving.participating.agreeing.doubting.misunderstanding.following.trotting.writing.clin.ing.interesting.damming.correlating.plugging.attending.retiring.beholding.understanding.walking.pinpointing.photographing.braking.soaking.folding.remembering.slin.ing.borrowing.rocking.allowing.filming.obeying.coiling.cycling.untidying.shrinking.preferring.stirring.fixing.attending.baking.saying.rotting.learning.governing.confessing.reminding.utilizing.bruising.dramatizing.knowing.puncturing.shearing.suggesting.achieving.heading.sliding.punching.greeting.gazing.swin.ing.spending.occurring.sneezing.creating.sparking.hiding.stitching.promoting.changing.snowing.taking.lying.reading.responding.bouncing.baking.pecking.multiplying.conserving.challenging.losing.sowing.fooling.marketing.informing.spilling.matching.speaking.dealing.detecting.rating.screwing.bruising.interlaying.phoning.ensuring.binding.stoping.scattering.weighing.participating.editing.letting.publicizing.preparing.financing.shearing.checking.writing.exciting.firing.bombing.disliking.restoring.eating.fighting.answering.balancing.sending.blotting.amusing.disagreeing.innovating.relying.correcting.confronting.judging.reducing.entertaining.arguing.selecting.stamping.parking.naming.noticing.doing.chopping.banging.engineering.trusting.describing.delegating.cheating.lending.mistaking.squeaking.winding.comparing.adapting.cracking.correlating.scolding.blushing.scraping.buzzing.existing.improvising.praising.splitting.distributing.curing.overdoing.mapping.progressing.activating.feeding.forgiving.dressing.manning.polishing.smoking.reconciling.knowing.tugging.being.causing.shutting.preventing.disappearing.presenting.banging.explaining.crossing.predicting.converting.sighing.designing.fooling.bursting.decorating.battling.hearing.sensing.meaning.presetting.chasing.overdrawing.classifying.charging.parting.polishing.planting.sniffing.fearing.commanding.formulating.bruising.distributing.officiating.seeking.offending.harming.computing.realigning.touring.containing.revising.surprising.helping.pleading.overflowing.reinforcing.nodding.matching.barring.ascertaining.budgeting.allowing.lightening.presetting.deceiving.collecting.slitting.becoming.collecting.cleaning.extending.boiling.overthrowing.obeying.working.painting.dealing.protecting.mugging.flin.ing.updating.referring.skiing.discovering.blinking.spelling.calling.curling.dealing.quitting.shaking.meaning.diverting.smiling.facilitating.satisfying.rolling.siting.asking.holding.blowing.kneeling.assuring.defining.disproving.recruiting.diagnosing.whispering.coughing.lasting.racing.sprouting.acquiring.stitching.heading.soothsaying.parking.splitting.programming.starting.including.knitting.making.jumping.staining.sensing.nominating.regulating.receiving.lasting.boxing.preceding.inventing.increasing.implementing.radiating.relaxing.guarding.brushing.heaping.killing.objecting.confronting.keeping.vexing.accomplishing.orienteering.sinking.repairing.instituting.coughing.preaching.juggling.trading.frying.lightening.scaring.hypothesizing.insuring.sealing.shoeing.grinning.ranking.teaching.coaching.creeping.rising.rubbing.bowing.systemizing.jamming.performing.framing.delaying.quitting.experimenting.smashing.leveling.skipping.sealing.breeding.blinking.beginning.owing.clearing.breaking.growing.guaranteeing.numbering.formulating.standing.verbalizing.executing.shaking.foreseeing.delighting.sneaking.hooking.pasting.objecting.coloring.setting.instructing.generating.measuring.glueing.reconciling.challenging.avoiding.missing.attaining.forecasting.tipping.sharing.bleaching.addressing.proofreading.intending.parting.queueing.crushing.sucking.monitoring.overcoming.copying.restructuring.chewing.casting.tying.ignoring.painting.examining.doubling.doubting.wishing.helping.spiting.wending.thrusting.splitting.muddling.confusing.liking.recognizing.designing.sending.reconciling.inducing.keeping.unifying.excusing.buzzing.joking.forgiving.conserving.budgeting.scratching.initiating.bumping.stamping.suspending.leveling.liking.scribbling.stinking.exhibiting.structuring.rating.queueing.belonging.fearing.broadcasting.hurrying.packing.brushing.glueing.tricking.wandering.bathing.inventorying.expanding.launching.reinforcing.soothing.communicating.predicting.simplifying.pressing.living.exceeding.spotting.disapproving.calculating.spotting.strapping.correcting.rotting.owing.bursting.encouraging.unpacking.cutting.originating.sketching.consisting.causing.affording.impressing.producing.hammering.sensing.scratching.borrowing.transforming.modifying.killing.besetting.lightening.spreading.mediating.sketching.wobbling.staring.adopting.strapping.laying.buying.biding.boasting.possessing.solving.expecting.covering.matching.accepting.rejecting.drying.mattering.blessing.cheering.hugging.wrapping.curing.attempting.meeting.sprin.ing.dressing.using.alighting.speeding.conceiving.meddling.losing.stimulating.clearing.forgetting.rocking.appreciating.rejoicing.increasing.rising.eating.critiquing.depending.spraying.keeping.researching.slapping.requesting.claiming.harassing.betting.crying.mending.irritating.concentrating.summarizing.enforcing.exercising.handwriting.supplying.acquiring.purchasing.lecturing.competing.compiling.beating.binding.bleeding.encouraging.charging.tutoring.kissing.testing.fetching.soothsaying.ending.arriving.sipping.appearing.nominating.praying.arranging.overdrawing.hiding.leaving.entering.maintaining.zooming.investigating.tempting.satisfying.suggesting.flowing.extracting.covering.treating.reigning.handling.bathing.upholding.facilitating.swelling.mending.slipping.paddling.mugging.belonging.pinpointing.wailing.pinching.excusing.occurring.ordering.preparing.assessing.parking.transforming.timing.grating.reflecting.groaning.snowing.shutting.checking.organizing.finding.digging.curving.filling.smoking.folding.releasing.locking.finalizing.installing.radiating.crawling.doing.admiring.telephoning.challenging.contracting.puncturing.deserving.owning.peeling.scorching.dispensing.resolving.plugging.disappearing.hypothesizing.parking.interrupting.exhibiting.rejoicing.reorganizing.bouncing.misunderstanding.choosing.deserving.killing.critiquing.mattering.realizing.swimming.passing.transforming.caring.bowing.professing.pinching.appraising.reminding.publicizing.reaching.leaning.knitting.typing.expecting.delivering.choking.seeing.licking.flapping.clarifying.symbolizing.stealing.trapping.drafting"; -test "init game" { +test "game init" { const ta = std.testing.allocator; const input = "[\"alice\", \"bob\"]"; var stream = std.json.TokenStream.init(input); - const players = try std.json.parse([]Player, &stream, .{ .allocator = ta }); - defer std.json.parseFree([]Player, players, .{ .allocator = ta }); + var players = try std.json.parse([]Player, &stream, .{ .allocator = ta }); - var game = Game.init(ta, players); - defer game.deinit(); + var game: Game = undefined; + try game.init(ta, players); + // defer game.deinit(ta); try std.testing.expectEqualStrings(game.current_judge, "alice"); try std.testing.expect(game.players.len == 2); - try std.testing.expect(game.rounds.items.len == 0); + try std.testing.expect(game.rounds.len == 0); + for (game.players) |player| { try std.testing.expect(player.score == 0); } + + var data = try game.toJson(ta); + defer ta.free(data); + try game.fromJson(ta, data); + + for ([_]u8{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }) |_| { + game.inc_version(); + } + try std.testing.expect(game.version == 10); } diff --git a/games/punderplay/src/main.zig b/games/punderplay/src/main.zig index 9604875..aab7bf0 100644 --- a/games/punderplay/src/main.zig +++ b/games/punderplay/src/main.zig @@ -3,18 +3,21 @@ const extism_pdk = @import("extism-pdk"); const Plugin = extism_pdk.Plugin; const json = std.json; const game = @import("game.zig"); +const store = @import("store.zig"); const VAR_STATE = "state"; pub fn main() void {} -pub fn initGame(config: game.Config, allocator: std.mem.Allocator) game.Game { - return game.Game.init(allocator, config.player_ids); +pub fn initGame(allocator: std.mem.Allocator, config: game.Config, state: store.Store) !i32 { + var gameState: game.Game = undefined; + try gameState.init(allocator, config.player_ids); + state.set(VAR_STATE, try gameState.toJson(allocator)); + return 0; } const LiveEvent = struct { player_id: []const u8, - event_name: []const u8, value: EventPayload, }; @@ -23,11 +26,17 @@ const EventPayload = struct { pun: []const u8, }; -pub fn handleEvent(event: LiveEvent, state: *game.Game) *game.Game { +pub fn handleEvent(allocator: std.mem.Allocator, event: LiveEvent, state: store.Store) i32 { + // var gameState = game.Game.fromJson(allocator, state.get(VAR_STATE)); + // _ = gameState; + // switch (event.event_name) {} + + _ = allocator; _ = event; + _ = state; - return state; + return 0; } const Assigns = struct {}; @@ -46,12 +55,10 @@ export fn init_game() i32 { const config = json.parse(game.Config, &stream, .{ .allocator = plugin.allocator }) catch unreachable; defer json.parseFree(game.Config, config, .{ .allocator = plugin.allocator }); - var gameState = initGame(config, plugin.allocator); - defer gameState.deinit(); - - plugin.setVar(VAR_STATE, gameState.to_json()); + var pluginStore = store.PluginStore.init(&plugin); + var state = store.Store.init(&pluginStore); - return 0; + return initGame(plugin.allocator, config, state) catch -1; } export fn handle_event() i32 { @@ -63,15 +70,10 @@ export fn handle_event() i32 { const event = json.parse(LiveEvent, &stream, .{ .allocator = plugin.allocator }) catch unreachable; defer json.parseFree(LiveEvent, event, .{ .allocator = plugin.allocator }); - var gameState = game.Game.from_json(plugin.allocator, plugin.getVar(VAR_STATE) catch unreachable orelse "{}"); - defer gameState.deinit(); - - var newGameState = handleEvent(event, &gameState); - defer newGameState.deinit(); + var pluginStore = store.PluginStore.init(&plugin); + var state = store.Store.init(&pluginStore); - plugin.setVar(VAR_STATE, newGameState.*.to_json()); - - return 0; + return handleEvent(plugin.allocator, event, state); } // export fn render(input: []const u8) i32 { diff --git a/games/punderplay/src/store.zig b/games/punderplay/src/store.zig index e29f828..a70cde0 100644 --- a/games/punderplay/src/store.zig +++ b/games/punderplay/src/store.zig @@ -9,6 +9,10 @@ pub const PluginStore = struct { const Self = @This(); + pub fn init(plugin: *Plugin) Self { + return Self{ .inner = plugin }; + } + pub fn get(self: Self, key: []const u8) []const u8 { return self.inner.getVar(key) catch unreachable orelse ""; } diff --git a/games/punderplay/zigmod.yml b/games/punderplay/zigmod.yml index 37fceb8..9ba9909 100644 --- a/games/punderplay/zigmod.yml +++ b/games/punderplay/zigmod.yml @@ -4,4 +4,3 @@ license: BSD-3 description: Pun-based game for GameBox demo root_dependencies: - src: git https://github.com/extism/zig-pdk - \ No newline at end of file From 89055cd523aa4c93785d2c103831db9803de6961 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Wed, 8 Feb 2023 12:32:02 -0700 Subject: [PATCH 8/9] wip: stopping point for now, nothx zig. not today. --- games/punderplay/build.zig | 5 ++- games/punderplay/src/game.zig | 26 ++++++++++---- games/punderplay/src/main.zig | 64 ++++++++++++++++++++++------------- games/punderplay/zigmod.lock | 2 +- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/games/punderplay/build.zig b/games/punderplay/build.zig index 9fdcbc4..f1eb833 100644 --- a/games/punderplay/build.zig +++ b/games/punderplay/build.zig @@ -3,7 +3,10 @@ const deps = @import("deps.zig"); pub fn build(b: *std.build.Builder) void { const mode = b.standardReleaseOptions(); - const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding } }); + // const target = b.standardTargetOptions(.{ .default_target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding } }); + const target = b.standardTargetOptions(.{ + .default_target = .{ .abi = .musl, .os_tag = .freestanding, .cpu_arch = .wasm32 }, + }); const exe = b.addExecutable("punderplay", "src/main.zig"); exe.setTarget(target); exe.setBuildMode(mode); diff --git a/games/punderplay/src/game.zig b/games/punderplay/src/game.zig index 894a7d8..5870ca6 100644 --- a/games/punderplay/src/game.zig +++ b/games/punderplay/src/game.zig @@ -1,15 +1,21 @@ const std = @import("std"); const Plugin = @import("extism-pdk").Plugin; +const store = @import("store.zig"); pub const Player = []const u8; pub const Judge = Player; -pub const Round = struct { - winner: Player, - winning_pun: []const u8, - judge: Judge, +pub const SubmittedPun = struct { prompt: [2][]const u8, + player: Player, +}; + +pub const Round = struct { + winner: ?Player, + winning_pun: ?[]const u8, + prompt: ?[2][]const u8, + submitted_puns: ?[]SubmittedPun, }; pub const Config = struct { @@ -43,6 +49,14 @@ pub const Game = struct { self.version = 0; } + pub fn getCurrentRound(self: *Self) Round { + return self.rounds[self.rounds.len - 1]; + } + + pub fn updateCurrentRound(self: *Self, round: Round) void { + self.rounds[self.rounds.len - 1] = round; + } + // pub fn deinit(self: *Game, allocator: std.mem.Allocator) void { // allocator.free(self.players); // } @@ -71,9 +85,9 @@ const verbs = "watering.cataloging.hunting.wanting.holding.taping.integrating.wo test "game init" { const ta = std.testing.allocator; - const input = "[\"alice\", \"bob\"]"; - var stream = std.json.TokenStream.init(input); + var stream = std.json.TokenStream.init("[\"alice\", \"bob\"]"); var players = try std.json.parse([]Player, &stream, .{ .allocator = ta }); + defer std.json.parseFree([]Player, players, .{ .allocator = ta }); var game: Game = undefined; try game.init(ta, players); diff --git a/games/punderplay/src/main.zig b/games/punderplay/src/main.zig index aab7bf0..8bed39c 100644 --- a/games/punderplay/src/main.zig +++ b/games/punderplay/src/main.zig @@ -3,43 +3,49 @@ const extism_pdk = @import("extism-pdk"); const Plugin = extism_pdk.Plugin; const json = std.json; const game = @import("game.zig"); -const store = @import("store.zig"); const VAR_STATE = "state"; pub fn main() void {} -pub fn initGame(allocator: std.mem.Allocator, config: game.Config, state: store.Store) !i32 { - var gameState: game.Game = undefined; - try gameState.init(allocator, config.player_ids); - state.set(VAR_STATE, try gameState.toJson(allocator)); - return 0; +pub fn initGame(allocator: std.mem.Allocator, config: game.Config) !game.Game { + var state: game.Game = undefined; + try state.init(allocator, config.player_ids); + return state; } const LiveEvent = struct { - player_id: []const u8, + player_id: game.Player, + event_name: []const u8, value: EventPayload, }; const EventPayload = struct { - prompt_id: usize, + prompt: [2][]const u8, pun: []const u8, }; -pub fn handleEvent(allocator: std.mem.Allocator, event: LiveEvent, state: store.Store) i32 { - // var gameState = game.Game.fromJson(allocator, state.get(VAR_STATE)); - // _ = gameState; - - // switch (event.event_name) {} +const EventUpdate = struct { + state: game.Game, + assigns: Assigns, +}; +pub fn handleEvent(allocator: std.mem.Allocator, event: LiveEvent, state: *game.Game, update: *EventUpdate) !void { _ = allocator; - _ = event; + _ = update; _ = state; - return 0; + if (std.mem.eql(u8, event.event_name, "submit-prompt")) {} + + return; } -const Assigns = struct {}; +const Assigns = struct { + is_judge: bool, + is_winner: ?bool, + submitted_pun: bool, + current_round: u8, +}; pub fn renderView(data: Assigns) i32 { _ = data; @@ -53,12 +59,18 @@ export fn init_game() i32 { var stream = json.TokenStream.init(input); const config = json.parse(game.Config, &stream, .{ .allocator = plugin.allocator }) catch unreachable; - defer json.parseFree(game.Config, config, .{ .allocator = plugin.allocator }); + // defer json.parseFree(game.Config, config, .{ .allocator = plugin.allocator }); // TODO: this causes an out of bounds memory access + + var state = initGame(plugin.allocator, config) catch unreachable; - var pluginStore = store.PluginStore.init(&plugin); - var state = store.Store.init(&pluginStore); + plugin.setVar(VAR_STATE, state.toJson(plugin.allocator) catch unreachable); - return initGame(plugin.allocator, config, state) catch -1; + debugOutput(plugin, state); + return 0; +} + +fn debugOutput(plugin: Plugin, state: game.Game) void { + plugin.output(state.toJson(plugin.allocator) catch unreachable); } export fn handle_event() i32 { @@ -70,10 +82,16 @@ export fn handle_event() i32 { const event = json.parse(LiveEvent, &stream, .{ .allocator = plugin.allocator }) catch unreachable; defer json.parseFree(LiveEvent, event, .{ .allocator = plugin.allocator }); - var pluginStore = store.PluginStore.init(&plugin); - var state = store.Store.init(&pluginStore); + const data = plugin.getVar(VAR_STATE) catch unreachable orelse return -1; + var state: game.Game = undefined; + state.fromJson(plugin.allocator, data) catch unreachable; - return handleEvent(plugin.allocator, event, state); + var eventUpdate: EventUpdate = undefined; + handleEvent(plugin.allocator, event, &state, &eventUpdate) catch unreachable; + + plugin.setVar(VAR_STATE, state.toJson(plugin.allocator) catch unreachable); + + return 0; } // export fn render(input: []const u8) i32 { diff --git a/games/punderplay/zigmod.lock b/games/punderplay/zigmod.lock index e72e3b8..c4e90b4 100644 --- a/games/punderplay/zigmod.lock +++ b/games/punderplay/zigmod.lock @@ -1,2 +1,2 @@ 2 -git https://github.com/extism/zig-pdk commit-0ee480666df11ad5c3b4fe2cfa47c68da4a7aa73 +git https://github.com/extism/zig-pdk commit-80821d1ded365580e366339a009d786f016c014c From f681b2051375bd7bf149fdf3e6ac4374fd4298c8 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Wed, 8 Feb 2023 16:48:06 -0700 Subject: [PATCH 9/9] chore: rename punderplay dir --- games/{punderplay => punderplay-zig}/.gitignore | 0 games/{punderplay => punderplay-zig}/README.md | 0 games/{punderplay => punderplay-zig}/build.zig | 0 games/{punderplay => punderplay-zig}/deps.zig | 0 games/{punderplay => punderplay-zig}/src/game.zig | 0 games/{punderplay => punderplay-zig}/src/main.zig | 0 games/{punderplay => punderplay-zig}/src/store.zig | 0 games/{punderplay => punderplay-zig}/zigmod.lock | 0 games/{punderplay => punderplay-zig}/zigmod.yml | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename games/{punderplay => punderplay-zig}/.gitignore (100%) rename games/{punderplay => punderplay-zig}/README.md (100%) rename games/{punderplay => punderplay-zig}/build.zig (100%) rename games/{punderplay => punderplay-zig}/deps.zig (100%) rename games/{punderplay => punderplay-zig}/src/game.zig (100%) rename games/{punderplay => punderplay-zig}/src/main.zig (100%) rename games/{punderplay => punderplay-zig}/src/store.zig (100%) rename games/{punderplay => punderplay-zig}/zigmod.lock (100%) rename games/{punderplay => punderplay-zig}/zigmod.yml (100%) diff --git a/games/punderplay/.gitignore b/games/punderplay-zig/.gitignore similarity index 100% rename from games/punderplay/.gitignore rename to games/punderplay-zig/.gitignore diff --git a/games/punderplay/README.md b/games/punderplay-zig/README.md similarity index 100% rename from games/punderplay/README.md rename to games/punderplay-zig/README.md diff --git a/games/punderplay/build.zig b/games/punderplay-zig/build.zig similarity index 100% rename from games/punderplay/build.zig rename to games/punderplay-zig/build.zig diff --git a/games/punderplay/deps.zig b/games/punderplay-zig/deps.zig similarity index 100% rename from games/punderplay/deps.zig rename to games/punderplay-zig/deps.zig diff --git a/games/punderplay/src/game.zig b/games/punderplay-zig/src/game.zig similarity index 100% rename from games/punderplay/src/game.zig rename to games/punderplay-zig/src/game.zig diff --git a/games/punderplay/src/main.zig b/games/punderplay-zig/src/main.zig similarity index 100% rename from games/punderplay/src/main.zig rename to games/punderplay-zig/src/main.zig diff --git a/games/punderplay/src/store.zig b/games/punderplay-zig/src/store.zig similarity index 100% rename from games/punderplay/src/store.zig rename to games/punderplay-zig/src/store.zig diff --git a/games/punderplay/zigmod.lock b/games/punderplay-zig/zigmod.lock similarity index 100% rename from games/punderplay/zigmod.lock rename to games/punderplay-zig/zigmod.lock diff --git a/games/punderplay/zigmod.yml b/games/punderplay-zig/zigmod.yml similarity index 100% rename from games/punderplay/zigmod.yml rename to games/punderplay-zig/zigmod.yml