class Gameworks::Game

Constants

DEFAULT_DELAY
STATE_COMPLETED
STATE_INITIATING
STATE_IN_PLAY
TURN_TIME_LIMIT

Attributes

delay_time[R]
id[R]
moves[R]
notifier[R]
players[R]
state[R]

Public Class Methods

new(payload={}) click to toggle source
# File lib/gameworks/game.rb, line 17
def initialize(payload={})
  @notifier = Notifier.new
  @players = []
  @state = STATE_INITIATING
  @delay_time = payload['delay_time'] || DEFAULT_DELAY
  @turns = {}
  @observers = {}
  @fuses = {}
  @id = generate_uuid.split('-').first
  @moves = {}
end

Public Instance Methods

active_players() click to toggle source
# File lib/gameworks/game.rb, line 99
def active_players
  raise NotImplementedError
end
add_move(payload, player) click to toggle source
# File lib/gameworks/game.rb, line 124
def add_move(payload, player)
  @fuses[player].abort

  move, error = build_move(payload, player)
  return false, error unless move

  legal, error = move_legal?(move, player)
  return false, error unless legal

  moves[player] = move
  process_move(move, player)

  ignore_disqualified_players
  update_observers
  true
end
add_player(payload={}) click to toggle source
# File lib/gameworks/game.rb, line 79
def add_player(payload={})
  return false if full?

  player = player_class.new(payload)
  return false unless player.valid?

  @players << player
  update_observers
  player
end
as_json(for_player=nil) click to toggle source
# File lib/gameworks/game.rb, line 183
def as_json(for_player=nil)
  { :id      => id,
    :players => @players.map{ |player| player.as_json(for_player) },
    :state   => @state }
end
build_move(payload, player) click to toggle source
# File lib/gameworks/game.rb, line 141
def build_move(payload, player)
  raise NotImplementedError
end
delta(snapshot, for_player=nil) click to toggle source
# File lib/gameworks/game.rb, line 57
def delta(snapshot, for_player=nil)
  { :id => id,
    :players => @players.select{ |p| player_changed?(p, snapshot, for_player) }.map{ |p| p.as_json(for_player) },
    :state   => @state }
end
disqualify(player) click to toggle source
# File lib/gameworks/game.rb, line 157
def disqualify(player)
  player.disqualify!
  update_observers
  if @players.select { |p| !p.disqualified? }.size < 2
    end_game
  elsif !waiting_on_moves?
    signal_turns
  end
  # else do nothing; waiting for other players
end
end_game() click to toggle source
# File lib/gameworks/game.rb, line 168
def end_game
  @state = STATE_COMPLETED
  @fuses.values.each(&:abort)
  update_observers(true)
  @players.each{ |p| p.signal_turn(nil) }
end
full?() click to toggle source
# File lib/gameworks/game.rb, line 63
def full?
  raise NotImplementedError
end
generate_uuid() click to toggle source
# File lib/gameworks/game.rb, line 95
def generate_uuid
  SecureRandom.uuid
end
ignore_disqualified_players() click to toggle source
# File lib/gameworks/game.rb, line 103
def ignore_disqualified_players
  @players.rotate! while @players.first.disqualified?
end
init_game() click to toggle source
# File lib/gameworks/game.rb, line 90
def init_game
  @players.shuffle!
  @state = STATE_IN_PLAY
end
player_changed?(player, snapshot, for_player=nil) click to toggle source
# File lib/gameworks/game.rb, line 53
def player_changed?(player, snapshot, for_player=nil)
  player.score != snapshot.player_scores[player]
end
player_class() click to toggle source
# File lib/gameworks/game.rb, line 67
def player_class
  Gameworks::Player
end
player_for_token(token) click to toggle source
# File lib/gameworks/game.rb, line 120
def player_for_token(token)
  @turns.delete(token)
end
process_move(move, player) click to toggle source
# File lib/gameworks/game.rb, line 149
def process_move(move, player)
  raise NotImplementedError
end
register_observer(cb) click to toggle source
# File lib/gameworks/game.rb, line 29
def register_observer(cb)
  token = generate_uuid
  @observers[token] = [self.snapshot, cb]
  token
end
signal_turns() click to toggle source
# File lib/gameworks/game.rb, line 107
def signal_turns
  moves.clear
  active_players.each do |player|
    token = generate_uuid
    @turns[token] = player
    # This may no longer be necessary, since we abort the players' fuses
    # when they submit turns in #add_move.
    @fuses[player].abort if @fuses[player]
    @fuses[player] = Gameworks::Fuse.new(TURN_TIME_LIMIT) { disqualify(player) }
    player.signal_turn(token)
  end
end
snapshot() click to toggle source
# File lib/gameworks/game.rb, line 179
def snapshot
  snapshot_class.new(self)
end
snapshot_class() click to toggle source
# File lib/gameworks/game.rb, line 175
def snapshot_class
  Gameworks::Game::Snapshot
end
snapshot_for_observer(token) click to toggle source
# File lib/gameworks/game.rb, line 44
def snapshot_for_observer(token)
  snapshot = nil
  if @observers.has_key?(token)
    snapshot, cb = @observers[token]
    @observers[token][0] = self.snapshot
  end
  snapshot
end
start_if_ready() click to toggle source
# File lib/gameworks/game.rb, line 71
def start_if_ready
  if full?
    init_game
    signal_turns
    update_observers
  end
end
to_json(for_player=nil) click to toggle source
# File lib/gameworks/game.rb, line 189
def to_json(for_player=nil)
  as_json(for_player).to_json
end
update_observers(end_game = false) click to toggle source
# File lib/gameworks/game.rb, line 35
def update_observers(end_game = false)
  @observers.each do |token, (_, cb)|
    snapshot = snapshot_for_observer(token)
    cb.call(delta(snapshot).to_json)
    cb.succeed if end_game
  end
  notifier.push(self, to_json)
end
waiting_on_moves?() click to toggle source
# File lib/gameworks/game.rb, line 153
def waiting_on_moves?
  (active_players - moves.keys).any?
end