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| { for (game.grid) |cell| {
if (cell == .empty) full = false; if (cell == .empty) full = false;
} }
if (full) {
game.victor = .tie;
return;
}
const patterns = [_][3]usize{ const patterns = [_][3]usize{
.{ 0, 1, 2 }, .{ 0, 1, 2 },
@ -77,7 +73,15 @@ pub fn evaluate(game: *Game) void {
} }
std.debug.assert(!(cpu_victor and player_victor)); std.debug.assert(!(cpu_victor and player_victor));
if (cpu_victor) game.victor = .cpu; if (cpu_victor) {
if (player_victor) game.victor = .player; 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 const Channel = struct {
pub fn open(channel: jetzig.channels.Channel) !void { 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); if (state.get("cells") == null) try initGame(channel);
try channel.sync(); try channel.sync();
} }
pub const Actions = struct { 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 { 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 { const cells = state.getT(.array, "cells") orelse {
return; return;
}; };
@ -42,14 +46,14 @@ pub const Channel = struct {
}; };
fn resetGame(channel: jetzig.channels.Channel) !void { fn resetGame(channel: jetzig.channels.Channel) !void {
var state = try channel.connect("game"); var state = try channel.state("game");
try state.put("victor", null); try state.put("victor", null);
var cells = try state.put("cells", .array); var cells = try state.put("cells", .array);
for (0..9) |_| try cells.append(null); for (0..9) |_| try cells.append(null);
} }
fn initGame(channel: jetzig.channels.Channel) !void { 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); var results = try state.put("results", .object);
try results.put("cpu", 0); try results.put("cpu", 0);
try results.put("player", 0); try results.put("player", 0);
@ -74,7 +78,7 @@ pub const Channel = struct {
} }
fn setVictor(channel: jetzig.channels.Channel, victor: Game.State) !void { 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)); try state.put("victor", @tagName(victor));
var results = state.getT(.object, "results") orelse return; var results = state.getT(.object, "results") orelse return;
const count = results.getT(.integer, @tagName(victor)) orelse return; const count = results.getT(.integer, @tagName(victor)) orelse return;

View File

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

View File

@ -17,10 +17,13 @@ pub fn RoutedChannel(Routes: type) type {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
websocket: *jetzig.websockets.RoutedWebsocket(Routes), websocket: *jetzig.websockets.RoutedWebsocket(Routes),
state: *jetzig.data.Value, root_state: *jetzig.data.Value,
data: *jetzig.data.Data, data: *jetzig.data.Data,
_connections: *std.StringHashMap(Connection), _connections: *std.StringHashMap(Connection),
route: jetzig.channels.Route,
env: Env, env: Env,
path: []const u8,
host: []const u8,
const Connection = struct { const Connection = struct {
state: *jetzig.data.Value, state: *jetzig.data.Value,
@ -34,9 +37,12 @@ pub fn RoutedChannel(Routes: type) type {
return .{ return .{
.allocator = allocator, .allocator = allocator,
.websocket = websocket, .websocket = websocket,
.state = try websocket.getState(), .root_state = try websocket.getState(),
.data = websocket.data, .data = websocket.data,
._connections = connections, ._connections = connections,
.route = websocket.route,
.path = websocket.path,
.host = websocket.host,
.env = .{ .env = .{
.store = websocket.store, .store = websocket.store,
.cache = websocket.cache, .cache = websocket.cache,
@ -84,9 +90,9 @@ pub fn RoutedChannel(Routes: type) type {
) catch {}; ) 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| { 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. // given scope.
return cached.state; 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 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 channel_state = try channel.websocket.channels.get(channel.data, connection_key) orelse blk: {
const state = try channel.data.object(); const channel_state = try channel.data.object();
try channel.websocket.channels.put(connection_key, state); try channel_state.put("__connection_key__", try std.fmt.allocPrint(channel.allocator, "http://{s}{s}?key={s}", .{ channel.host, channel.path, connection_key }));
break :blk state; try channel.websocket.channels.put(connection_key, channel_state);
break :blk channel_state;
}; };
try channel._connections.put(scope, .{ .key = connection_key, .state = state }); try channel._connections.put(scope, .{ .key = connection_key, .state = channel_state });
return 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( pub fn getT(
channel: Channel, channel: Channel,
comptime T: jetzig.data.Data.ValueType, comptime T: jetzig.data.Data.ValueType,
key: []const u8, key: []const u8,
) @TypeOf(channel.state.getT(T, key)) { ) @TypeOf(channel.root_state.getT(T, key)) {
return channel.state.getT(T, key); return channel.root_state.getT(T, key);
} }
pub fn get(channel: Channel, key: []const u8) ?*jetzig.data.Value { 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( pub fn put(
channel: Channel, channel: Channel,
key: []const u8, key: []const u8,
value: anytype, value: anytype,
) @TypeOf(channel.state.put(key, value)) { ) @TypeOf(channel.root_state.put(key, value)) {
return try channel.state.put(key, value); return try channel.root_state.put(key, value);
} }
pub fn remove(channel: Channel, key: []const u8) bool { 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 { 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(); var it = channel._connections.iterator();
while (it.next()) |entry| { while (it.next()) |entry| {

View File

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

View File

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