import 'package:dartmcts/net.dart'; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as shelf_io; import 'dart:convert'; import 'package:uuid/uuid.dart'; Function? gameHandler; void serve(TrainableInterface Function() trainer) async { var handler = const Pipeline().addMiddleware(logRequests()).addHandler(_handleRequest); gameHandler = () => trainer.call(); var server = await shelf_io.serve(handler, 'localhost', 5000); print('Serving at http://${server.address.host}:${server.port}'); } Map<String, TrainableInterface> gamesInProgress = {}; Future<Response> _handleRequest(Request request) async { if (request.url.path == "newgame") { TrainableInterface game = gameHandler?.call(); var uuid = const Uuid(); String id = uuid.v4().toString(); gamesInProgress[id] = game; return Response.ok( json.encode({ "id": id, "player_count": game.playerCount, "action_space_size": game.actionSpaceSize, "observation_space_size": game.observationSpaceSize, "current_player": game.currentPlayer, "observation": game.observation(), "legal_actions": game.legalActions() }), headers: {'Content-Type': 'application/json'}); } else { var pieces = request.url.path.split('/'); assert(pieces[0] == "step"); var id = pieces[1]; var action = json.decode(await request.readAsString())['action']; TrainableInterface? game = gamesInProgress[id]!; var gameResponse = game.step(action); var stepResponse = json.encode({ "observation": game.observation(), "legal_actions": game.legalActions(), "next_player": game.currentPlayer, "reward": gameResponse.reward, "done": gameResponse.done }); if (gameResponse.done) { // free memory for finished games gamesInProgress.remove(id); game = null; } return Response.ok(stepResponse, headers: {'Content-Type': 'application/json'}); } }