Gameworks
About
Gameworks is a framework for creating turn-based games hosted by a server, that can be interacted with via an API. At Instructure, we use it to create games for the final round of our coding competition: Mebipenny.
Installation
Add gem 'gameworks'
to your Gemfile, or install manually with gem install gameworks
Usage
You will create classes to extend this engine, and then be able to interact with the game via an API. Let's go over how all that works.
Implementation
At minimum, you'll need a 3 files, that will look something like the following:
config.ru
:
#!ruby
require_relative 'your_game/server'
use Rack::CommonLogger
# Override Lint middleware to handle async callback (-1 http response)
module Rack
class Lint
def call(env = nil)
@app.call(env)
end
end
end
run YourGame::Server.new
your_game/server.rb
:
require 'gameworks'
require_relative 'game'
module YourGame
class Server < Gameworks::Server
def game_class
YourGame::Game
end
end
end
your_game/game.rb
:
require 'gameworks'
module YourGame
class Game < Gameworks::Game
# you're reached player capacity
def full?
end
# an array of players currently taking a turn
def active_players
end
# given a json payload, create a move object
def build_move(payload, player)
end
# given a move object, is it legal
def move_legal?(move, player)
end
# given a lecal move, apply it
def process_move(move, player)
end
end
end
API Data Types
The following are the default request/response data. You game implementation may extend any/all of these.
New Player (request)
{name: <string>}
Player (response)
{name: <string>,
score: <integer>,
disqualified: <boolean>}
New Game (request)
Nothing by default, determined by your game implementation.
Game (response)
{players: [<Player>*],
state: <Game State>}
players is the set of Players joined to the game.
Game Delta (response)
[
players is the set of Players whose scores have changed since the request began.
Game State (response)
'initiating', 'in play', or 'completed'
See descriptions of game states below.
New Move (request)
Nothing by default, determined by your game implementation.
Using the API
Starting a Game
To spawn a new game on the server, POST to / with a New Game object as payload.
You will receive a 201 Created response with the game's root path (henceforth
Game States
Initiating
The game begins in this state. You join a game by POSTing to
If you successfully join the game, you will receive a 200 OK response at the beginning of your first turn, with a Game object as response payload. This response will include an X-Turn-Token HTTP response header.
If the game is no longer in this state (i.e. the game is full and has begun) when you POST, you will receive a 410 Gone response indicating the game can no longer be joined.
Once the game is full the game moves to the in play state.
In Play
In this state, players POST to
After receiving a 200 OK response to a
If the move POSTed is illegal, you will receive an immediate 403 Forbidden response describing the violation. You are disqualified and the game moves to the completed state.
Otherwise, you will receive a 200 OK response at the beginning of your next turn, with a Game Delta object. This response will include an X-Turn-Token response header to be used in your next move.
After a 200 OK response, the game may have moved to the completed state. This state change will be indicated in the Game Delta object. Once the game is completed, further moves are ignored with a 410 Gone response.
Completed
Play is complete. Game state can still be pulled, but no new POSTs are accepted.
Idempotent View
At any point, the full game state can be requested with a GET request to
Observers (v1)
(Intended for use by game viewer, but may be used by others.)
At any point, an observer may be registered by POSTing to
You will receive an immediate 200 OK response with the first document, a Game object. After this, the response will remain open and new Game Delta objects will be returned as events occur.
The HTTP response will end when the game ends, after the final Game Delta object is sent.
The POST request requires no payload. However, if the payload includes a "wrapper" key, then each JSON document will be fprint'ed into that text, replacing the first %s. For instance, a HTML comet technique:
{ "wrapper": "<script type='text/javascript'>myUpdater(%s);</script>\n" }
Observers (v2)
TODO: notes about push
Matchmaking
When you have a bot you'd like to try against others, but you don't want to set up a game yourself and you don't care who your opponent is, you can connect your bot to our dirt-simple (and stupid) matchmaking system.
Simply GET /match and wait for a response. You will be added to a matchmaking queue, and once there are at least two people in the queue, the front two will be popped and each given a 302 Redirect with a game's url in the Location HTTP response header.
If no one else is joining, feel free to request a match against any of our bots! (Our bots are not eligible to win, so don't worry.)