Class: Match

Inherits:
Object
  • Object
show all
Includes:
Mongoid::Document, Mongoid::Timestamps::Updated
Defined in:
app/models/match.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.delete_irrelevant_matches!Object



74
75
76
77
# File 'app/models/match.rb', line 74

def self.delete_irrelevant_matches!
  finished.each { |m| m.delete }
  delete_matches_older_than! match_lifespan
end

.delete_match!(match_id) ⇒ Object



63
64
65
66
67
68
69
70
71
72
# File 'app/models/match.rb', line 63

def self.delete_match!(match_id)
  begin
    match = find match_id
  rescue
  else
    match.delete
  end

  self
end

.delete_matches_older_than!(lifespan) ⇒ Object



58
59
60
61
62
# File 'app/models/match.rb', line 58

def self.delete_matches_older_than!(lifespan)
  expired(lifespan).delete_all

  self
end

.finishedObject



21
22
23
# File 'app/models/match.rb', line 21

def self.finished
  all.select { |match| match.finished? }
end

.include_game_definitionObject



35
36
37
38
39
40
# File 'app/models/match.rb', line 35

def self.include_game_definition
  field :game_definition_key, type: Symbol
  validates_presence_of :game_definition_key
  field :game_definition_file_name
  field :game_def_hash, type: Hash
end

.include_nameObject



24
25
26
27
28
# File 'app/models/match.rb', line 24

def self.include_name
  field :name
  validates_presence_of :name
  validates_format_of :name, without: /^\s*$/
end

.include_name_from_userObject



29
30
31
32
33
34
# File 'app/models/match.rb', line 29

def self.include_name_from_user
  field :name_from_user
  validates_presence_of :name_from_user
  validates_format_of :name_from_user, without: /^\s*$/
  validates_uniqueness_of :name_from_user
end

.include_number_of_handsObject



41
42
43
44
45
# File 'app/models/match.rb', line 41

def self.include_number_of_hands
  field :number_of_hands, type: Integer
  validates_presence_of :number_of_hands
  validates_numericality_of :number_of_hands, greater_than: 0, only_integer: true
end

.include_opponent_namesObject



46
47
48
49
# File 'app/models/match.rb', line 46

def self.include_opponent_names
  field :opponent_names, type: Array
  validates_presence_of :opponent_names
end

.include_seatObject



50
51
52
# File 'app/models/match.rb', line 50

def self.include_seat
  field :seat, type: Integer
end

.include_user_nameObject



53
54
55
56
57
# File 'app/models/match.rb', line 53

def self.include_user_name
  field :user_name
  validates_presence_of :user_name
  validates_format_of :user_name, without: /^\s*$/
end

.match_lifespanObject



73
# File 'app/models/match.rb', line 73

def self.match_lifespan() 1.month end

.start_match(name, game_definition_key, user_name = User.DEFAULT_NAME, opponent_names = nil, seat = nil, number_of_hands = nil, random_seed = nil) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/models/match.rb', line 79

def self.start_match(
  name,
  game_definition_key,
  user_name = User.DEFAULT_NAME,
  opponent_names = nil,
  seat = nil,
  number_of_hands = nil,
  random_seed = nil
)
  new(
    "name_from_user" => name,
    "game_definition_key" => game_definition_key,
    'user_name' => user_name,
    "opponent_names" => opponent_names,
    'seat'=> seat,
    "number_of_hands" => number_of_hands,
    "random_seed" => random_seed
  ).finish_starting!
end

Instance Method Details

#bot_opponent_portsObject



201
202
203
204
205
206
207
# File 'app/models/match.rb', line 201

def bot_opponent_ports
  local_opponent_ports = opponent_ports
  human_opponent_ports.each do |port|
    local_opponent_ports.delete port
  end
  local_opponent_ports
end

#every_bot(dealer_host) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'app/models/match.rb', line 159

def every_bot(dealer_host)
  ap "port_numbers.length: #{port_numbers.length}, player_names: #{player_names}, bot_opponent_ports: #{bot_opponent_ports}, ApplicationDefs.bots(game_definition_key, opponent_names).length: #{ApplicationDefs.bots(game_definition_key, opponent_names).length}"

  raise unless port_numbers.length == player_names.length ||
    bot_opponent_ports.length == ApplicationDefs.bots(game_definition_key, opponent_names).length

  bot_opponent_ports.zip(
    ApplicationDefs.bots(game_definition_key, opponent_names)
  ).each do |port_num, bot|
    if bot.is_a?(Class)
      bot_argument_hash = {
        port_number: port_num,
        server: dealer_host,
        game_def: game_definition_file_name
      }

      yield bot.run_command(bot_argument_hash).split(' ')
    else # bot is a script that takes a host name and port in that order
      yield [bot, dealer_host, port_num]
    end
  end
end

#fcpa?Boolean

Returns:

  • (Boolean)


117
118
119
120
# File 'app/models/match.rb', line 117

def fcpa?
  return @is_fcpa unless @is_fcpa.nil?
  @is_fcpa = :two_player_fcpa == self.game_definition_key
end

#finish_starting!Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'app/models/match.rb', line 131

def finish_starting!
  local_name = name_from_user.strip
  self.name = local_name
  self.name_from_user = local_name

  game_info = ApplicationDefs.game_definitions[game_definition_key]

  # Adjust or initialize seat
  self.seat ||= ApplicationDefs.random_seat(game_info[:num_players])
  if seat > game_info[:num_players]
    seat = game_info[:num_players]
  end

  self.random_seed ||= ApplicationDefs.random_seed

  self.game_definition_file_name = game_info[:file]

  self.opponent_names ||= (game_info[:num_players] - 1).times.map { |i| "tester" }

  self.number_of_hands ||= 1

  save!

  self
end

#finished?Boolean

Returns:

  • (Boolean)


121
122
123
124
125
126
127
128
129
130
# File 'app/models/match.rb', line 121

def finished?
  !slices.empty? && (
    slices.last.match_ended? || -> do
      state = AcpcPokerTypes::MatchState.parse(
        slices.last.state_string
      )
      state.hand_ended?(game_def) && state.hand_number >= self.number_of_hands - 1
    end.call
  )
end

#game_defObject



111
112
113
# File 'app/models/match.rb', line 111

def game_def
  @game_def ||= AcpcPokerTypes::GameDefinition.new(self.game_def_hash)
end

#human_opponent_portsObject



198
199
200
# File 'app/models/match.rb', line 198

def human_opponent_ports
  human_opponent_seats.map { |human_opp_seat| port_numbers[human_opp_seat - 1] }
end

#human_opponent_seats(opponent_user_name = nil) ⇒ Object



189
190
191
192
193
194
195
196
197
# File 'app/models/match.rb', line 189

def human_opponent_seats(opponent_user_name = nil)
  player_names.each_index.select do |i|
    if opponent_user_name
      player_names[i] == opponent_user_name
    else
      User.where(name: player_names[i]).exists?
    end
  end.map { |s| s + 1 } - [self.seat]
end

#no_limit?Boolean

Returns:

  • (Boolean)


114
115
116
# File 'app/models/match.rb', line 114

def no_limit?
  @is_no_limit ||= game_def.betting_type == AcpcPokerTypes::GameDefinition::BETTING_TYPES[:nolimit]
end

#opponent_portsObject



184
185
186
187
188
# File 'app/models/match.rb', line 184

def opponent_ports
  local_port_numbers = port_numbers.dup
  users_port = local_port_numbers.delete_at(seat - 1)
  local_port_numbers
end

#player_namesObject



156
157
158
# File 'app/models/match.rb', line 156

def player_names
  opponent_names.dup.insert seat-1, self.user_name
end

#rejoinable_seats(user_name) ⇒ Object



208
209
210
211
212
213
214
# File 'app/models/match.rb', line 208

def rejoinable_seats(user_name)
  (
    self.human_opponent_seats(user_name) -
    # Remove seats already taken by players who have already joined this match
    Match.where(name: self.name).ne(name_from_user: self.name).map { |m| m.seat }
  )
end

#users_portObject



181
182
183
# File 'app/models/match.rb', line 181

def users_port
  port_numbers[seat - 1]
end