Class: Gameworks::Game

Inherits:
Object
  • Object
show all
Defined in:
lib/gameworks/game.rb,
lib/gameworks/game_snapshot.rb

Defined Under Namespace

Classes: Snapshot

Constant Summary collapse

TURN_TIME_LIMIT =
30
DEFAULT_DELAY =
0.3
STATE_INITIATING =
'initiating'
STATE_IN_PLAY =
'in play'
STATE_COMPLETED =
'completed'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(payload = {}) ⇒ Game

Returns a new instance of Game.



16
17
18
19
20
21
22
23
24
# File 'lib/gameworks/game.rb', line 16

def initialize(payload={})
  @players = []
  @state = STATE_INITIATING
  @delay_time = payload['delay_time'] || DEFAULT_DELAY
  @turns = {}
  @observers = {}
  @fuses = {}
  @id = generate_uuid.split('-').first
end

Instance Attribute Details

#delay_timeObject (readonly)

Returns the value of attribute delay_time.



14
15
16
# File 'lib/gameworks/game.rb', line 14

def delay_time
  @delay_time
end

#idObject (readonly)

Returns the value of attribute id.



14
15
16
# File 'lib/gameworks/game.rb', line 14

def id
  @id
end

#playersObject (readonly)

Returns the value of attribute players.



14
15
16
# File 'lib/gameworks/game.rb', line 14

def players
  @players
end

#stateObject (readonly)

Returns the value of attribute state.



14
15
16
# File 'lib/gameworks/game.rb', line 14

def state
  @state
end

Instance Method Details

#active_playersObject

Raises:

  • (NotImplementedError)


94
95
96
# File 'lib/gameworks/game.rb', line 94

def active_players
  raise NotImplementedError
end

#add_move(payload, player) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/gameworks/game.rb', line 116

def add_move(payload, player)
  move, error = build_move(payload, player)
  return false, error unless move
  legal, error = move_legal?(move, player)
  return false, error unless legal
  legal, error = process_move(move, player)
  return false, error unless legal
  ignore_disqualified_players
  update_observers
  return true
end

#add_player(payload = {}) ⇒ Object



74
75
76
77
78
79
80
81
82
83
# File 'lib/gameworks/game.rb', line 74

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) ⇒ Object



166
167
168
169
# File 'lib/gameworks/game.rb', line 166

def as_json(for_player=nil)
  { :players => @players.map{ |player| player.as_json(for_player) },
    :state   => @state }
end

#build_move(payload, player) ⇒ Object

Raises:

  • (NotImplementedError)


128
129
130
# File 'lib/gameworks/game.rb', line 128

def build_move(payload, player)
  raise NotImplementedError
end

#delta(snapshot, for_player = nil) ⇒ Object



53
54
55
56
# File 'lib/gameworks/game.rb', line 53

def delta(snapshot, for_player=nil)
  { :players => @players.select{ |p| player_changed?(p, snapshot, for_player) }.map{ |p| p.as_json(for_player) },
    :state   => @state }
end

#disqualify(player) ⇒ Object



140
141
142
143
144
145
146
147
148
149
# File 'lib/gameworks/game.rb', line 140

def disqualify(player)
  player.score = 'disqualified'
  update_observers
  if @players.select { |p| !p.disqualified? }.size < 2
    end_game
  else
    update_observers
    end_turn
  end
end

#end_gameObject



151
152
153
154
155
156
# File 'lib/gameworks/game.rb', line 151

def end_game
  @state = STATE_COMPLETED
  @fuses.values.each(&:abort)
  update_observers(true)
  @players.each{ |p| p.signal_turn(nil) }
end

#full?Boolean

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


58
59
60
# File 'lib/gameworks/game.rb', line 58

def full?
  raise NotImplementedError
end

#generate_uuidObject



90
91
92
# File 'lib/gameworks/game.rb', line 90

def generate_uuid
  SecureRandom.uuid
end

#ignore_disqualified_playersObject



98
99
100
# File 'lib/gameworks/game.rb', line 98

def ignore_disqualified_players
  @players.rotate! while @players.first.disqualified?
end

#init_gameObject



85
86
87
88
# File 'lib/gameworks/game.rb', line 85

def init_game
  @players.shuffle!
  @state = STATE_IN_PLAY
end

#move_legal?(move, player) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


132
133
134
# File 'lib/gameworks/game.rb', line 132

def move_legal?(move, player)
  raise NotImplementedError
end

#player_changed?(player, snapshot, for_player = nil) ⇒ Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/gameworks/game.rb', line 49

def player_changed?(player, snapshot, for_player=nil)
  player.score != snapshot.player_scores[player]
end

#player_classObject



62
63
64
# File 'lib/gameworks/game.rb', line 62

def player_class
  Gameworks::Player
end

#player_for_token(token) ⇒ Object



112
113
114
# File 'lib/gameworks/game.rb', line 112

def player_for_token(token)
  @turns.delete(token)
end

#process_move(move, player) ⇒ Object

Raises:

  • (NotImplementedError)


136
137
138
# File 'lib/gameworks/game.rb', line 136

def process_move(move, player)
  raise NotImplementedError
end

#register_observer(cb) ⇒ Object



26
27
28
29
30
# File 'lib/gameworks/game.rb', line 26

def register_observer(cb)
  token = generate_uuid
  @observers[token] = [self.snapshot, cb]
  token
end

#signal_turnsObject



102
103
104
105
106
107
108
109
110
# File 'lib/gameworks/game.rb', line 102

def signal_turns
  active_players.each do |player|
    token = generate_uuid
    @turns[token] = player
    @fuses[player].abort if @fuses[player]
    @fuses[player] = Gameworks::Fuse.new(TURN_TIME_LIMIT) { disqualify(player) }
    player.signal_turn(token)
  end
end

#snapshotObject



162
163
164
# File 'lib/gameworks/game.rb', line 162

def snapshot
  snapshot_class.new(self)
end

#snapshot_classObject



158
159
160
# File 'lib/gameworks/game.rb', line 158

def snapshot_class
  Gameworks::Game::Snapshot
end

#snapshot_for_observer(token) ⇒ Object



40
41
42
43
44
45
46
47
# File 'lib/gameworks/game.rb', line 40

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_readyObject



66
67
68
69
70
71
72
# File 'lib/gameworks/game.rb', line 66

def start_if_ready
  if full?
    init_game
    signal_turns
    update_observers
  end
end

#to_json(for_player = nil) ⇒ Object



171
172
173
# File 'lib/gameworks/game.rb', line 171

def to_json(for_player=nil)
  as_json(for_player).to_json
end

#update_observers(end_game = false) ⇒ Object



32
33
34
35
36
37
38
# File 'lib/gameworks/game.rb', line 32

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
end