This commit is contained in:
Bob Farrell 2025-05-04 20:38:44 +01:00
parent 8074f8a221
commit c887b25ef8
6 changed files with 60 additions and 28 deletions

View File

@ -52,10 +52,6 @@ pub fn evaluate(game: *Game) void {
for (game.grid) |cell| {
if (cell == .empty) full = false;
}
if (full) {
game.victor = .tie;
return;
}
const patterns = [_][3]usize{
.{ 0, 1, 2 },
@ -77,7 +73,15 @@ pub fn evaluate(game: *Game) void {
}
std.debug.assert(!(cpu_victor and player_victor));
if (cpu_victor) game.victor = .cpu;
if (player_victor) game.victor = .player;
if (cpu_victor) {
game.victor = .cpu;
break;
}
if (player_victor) {
game.victor = .player;
break;
}
} else if (full) {
game.victor = .tie;
}
}

View File

@ -11,14 +11,18 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
pub const Channel = struct {
pub fn open(channel: jetzig.channels.Channel) !void {
var state = try channel.connect("game");
var state = try channel.state("game");
if (state.get("cells") == null) try initGame(channel);
try channel.sync();
}
pub const Actions = struct {
pub fn join(channel: jetzig.channels.Channel, token: []const u8) !void {
try channel.connect("game", token);
}
pub fn move(channel: jetzig.channels.Channel, cell: usize) !void {
var state = try channel.connect("game");
var state = try channel.state("game");
const cells = state.getT(.array, "cells") orelse {
return;
};
@ -42,14 +46,14 @@ pub const Channel = struct {
};
fn resetGame(channel: jetzig.channels.Channel) !void {
var state = try channel.connect("game");
var state = try channel.state("game");
try state.put("victor", null);
var cells = try state.put("cells", .array);
for (0..9) |_| try cells.append(null);
}
fn initGame(channel: jetzig.channels.Channel) !void {
var state = try channel.connect("game");
var state = try channel.state("game");
var results = try state.put("results", .object);
try results.put("cpu", 0);
try results.put("player", 0);
@ -74,7 +78,7 @@ pub const Channel = struct {
}
fn setVictor(channel: jetzig.channels.Channel, victor: Game.State) !void {
var state = try channel.connect("game");
var state = try channel.state("game");
try state.put("victor", @tagName(victor));
var results = state.getT(.object, "results") orelse return;
const count = results.getT(.integer, @tagName(victor)) orelse return;

View File

@ -43,6 +43,9 @@
></span>
<span>&#127942;</span>
</div>
<h4>Share this link to invite another player</h4>
<div jetzig-connect="$.__connect_url__"></div>
</jetzig-scope>
<script>

View File

@ -17,10 +17,13 @@ pub fn RoutedChannel(Routes: type) type {
allocator: std.mem.Allocator,
websocket: *jetzig.websockets.RoutedWebsocket(Routes),
state: *jetzig.data.Value,
root_state: *jetzig.data.Value,
data: *jetzig.data.Data,
_connections: *std.StringHashMap(Connection),
route: jetzig.channels.Route,
env: Env,
path: []const u8,
host: []const u8,
const Connection = struct {
state: *jetzig.data.Value,
@ -34,9 +37,12 @@ pub fn RoutedChannel(Routes: type) type {
return .{
.allocator = allocator,
.websocket = websocket,
.state = try websocket.getState(),
.root_state = try websocket.getState(),
.data = websocket.data,
._connections = connections,
.route = websocket.route,
.path = websocket.path,
.host = websocket.host,
.env = .{
.store = websocket.store,
.cache = websocket.cache,
@ -84,9 +90,9 @@ pub fn RoutedChannel(Routes: type) type {
) catch {};
}
pub fn connect(channel: Channel, comptime scope: []const u8) !*jetzig.data.Value {
pub fn state(channel: Channel, comptime scope: []const u8) !*jetzig.data.Value {
if (channel._connections.get(scope)) |cached| {
// Ensure an identical value is returned for each invocation of `connect` for a
// Ensure an identical value is returned for each invocation of `state` for a
// given scope.
return cached.state;
}
@ -108,41 +114,48 @@ pub fn RoutedChannel(Routes: type) type {
};
const connection_key = try std.fmt.allocPrint(channel.allocator, "{s}:{s}", .{ channel.websocket.session_id, connection_id });
const state = try channel.websocket.channels.get(channel.data, connection_key) orelse blk: {
const state = try channel.data.object();
try channel.websocket.channels.put(connection_key, state);
break :blk state;
const channel_state = try channel.websocket.channels.get(channel.data, connection_key) orelse blk: {
const channel_state = try channel.data.object();
try channel_state.put("__connection_key__", try std.fmt.allocPrint(channel.allocator, "http://{s}{s}?key={s}", .{ channel.host, channel.path, connection_key }));
try channel.websocket.channels.put(connection_key, channel_state);
break :blk channel_state;
};
try channel._connections.put(scope, .{ .key = connection_key, .state = state });
return state;
try channel._connections.put(scope, .{ .key = connection_key, .state = channel_state });
return channel_state;
}
pub fn connect(channel: Channel, comptime scope: []const u8, session_id: []const u8) !void {
_ = channel;
_ = scope;
_ = session_id;
}
pub fn getT(
channel: Channel,
comptime T: jetzig.data.Data.ValueType,
key: []const u8,
) @TypeOf(channel.state.getT(T, key)) {
return channel.state.getT(T, key);
) @TypeOf(channel.root_state.getT(T, key)) {
return channel.root_state.getT(T, key);
}
pub fn get(channel: Channel, key: []const u8) ?*jetzig.data.Value {
return channel.state.get(key);
return channel.root_state.get(key);
}
pub fn put(
channel: Channel,
key: []const u8,
value: anytype,
) @TypeOf(channel.state.put(key, value)) {
return try channel.state.put(key, value);
) @TypeOf(channel.root_state.put(key, value)) {
return try channel.root_state.put(key, value);
}
pub fn remove(channel: Channel, key: []const u8) bool {
return channel.state.remove(key);
return channel.root_state.remove(key);
}
pub fn sync(channel: Channel) !void {
try channel.websocket.syncState(channel.state, "__root__", channel.websocket.session_id);
try channel.websocket.syncState(channel.root_state, "__root__", channel.websocket.session_id);
var it = channel._connections.iterator();
while (it.next()) |entry| {

View File

@ -223,6 +223,8 @@ pub fn RoutedServer(Routes: type) type {
jetzig.websockets.Context{
.allocator = self.allocator,
.route = route,
.path = request.path.base_path,
.host = request.headers.getLower("host") orelse "",
.session_id = session_id,
.channels = self.channels,
.store = self.store,

View File

@ -13,6 +13,8 @@ pub const Context = struct {
cache: *jetzig.kv.Store.CacheStore,
job_queue: *jetzig.kv.Store.JobQueueStore,
logger: jetzig.loggers.Logger,
path: []const u8,
host: []const u8,
};
pub fn RoutedWebsocket(Routes: type) type {
@ -27,6 +29,8 @@ pub fn RoutedWebsocket(Routes: type) type {
data: *jetzig.Data,
session_id: []const u8,
logger: jetzig.loggers.Logger,
path: []const u8,
host: []const u8,
const Websocket = @This();
const router = jetzig.channels.ActionRouter.initComptime(Routes);
@ -45,6 +49,8 @@ pub fn RoutedWebsocket(Routes: type) type {
.cache = context.cache,
.job_queue = context.job_queue,
.logger = context.logger,
.path = context.path,
.host = context.host,
.data = data,
};
}