Module: Gameable

Included in:
Game, MiniGame
Defined in:
lib/minigame/gameable.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#strategy_profilesObject

Returns the value of attribute strategy_profiles.



2
3
4
# File 'lib/minigame/gameable.rb', line 2

def strategy_profiles
  @strategy_profiles
end

Instance Method Details

#best_response_against(opponent_strategy) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/minigame/gameable.rb', line 31

def best_response_against(opponent_strategy)
  best_resp=[]
  # get opponent player from strategy
  opp_player = player_from_strategy(opponent_strategy[:strategy]).first
  # get player from strategy
  player = players.detect{|x| x[:name] != opp_player[:name]}
  strat_payoff_list ||=[]
  # only collect possible payoffs that are opposed to the passed in opponent's strategy
  strat_payoff_list = player_strategy_profiles(player).inject([]) do |acc, str|
    if opposing_player_strategy_profile(str)[:strategy][:name]==opponent_strategy[:strategy][:name]
      acc << str
    end
    acc
  end
  best_resp = strat_payoff_list.sort{|x| x[:payoff]}.reverse
  # return top performer, later need to return all strategies that are equal in payoff
  best_resp.first
end

#better_or_equal_payoffs?(strategy_profile) ⇒ Boolean

Returns:

  • (Boolean)


268
269
270
# File 'lib/minigame/gameable.rb', line 268

def better_or_equal_payoffs?(strategy_profile)
  deviating_payoffs(strategy_profile).select{|x| x[:payoff] >= strategy_profile[:payoff]}
end

#better_payoffs?(strategy_profile) ⇒ Boolean

this should list all of the deviating payoffs for the opponent’s strategy within the passed in strategy profile. Only the payoffs corresponding to the opponent’s strategy are considered deviating payoffs

Returns:

  • (Boolean)


264
265
266
# File 'lib/minigame/gameable.rb', line 264

def better_payoffs?(strategy_profile)
  deviating_payoffs(strategy_profile).select{|x| x[:payoff] > strategy_profile[:payoff]}
end

#compare_deviating_strategy(strategy, deviation) ⇒ Object

for a strategy, take each strategy profile and match it against it’s corresonding but deviating strategy profile



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/minigame/gameable.rb', line 118

def compare_deviating_strategy(strategy, deviation)
  raise "invalid deviation for submitted strategy" if !valid_deviation?(strategy, deviation)

  one_equal = false
  one_better = false
  selected_profile_list = self.strategy_profiles.select{|x| x[:strategy][:name] == strategy[:name]}
  # loop through strategy profiles from the strategy
  selected_profile_list.each do |strat|
    # store strat payoff e.g. -2
    strat_payoff = strat[:payoff]
    opposing_strategy = opposing_player_strategy_profile(strat)
    # get deviating profile's payoff that corresponds to opposing strategy
    deviating_profile = self.strategy_profiles.select do |x| 
      x[:strategy][:name] == deviation[:name]  && opposing_player_strategy_profile(x)[:strategy][:name] == opposing_strategy[:strategy][:name]
    end
    # compare payoffs
    # if strategy payoff is better than even just one deviating 
    # payoff, the strategy is not dominated
    if strat_payoff > deviating_profile[0][:payoff]
      return :not_dominated
    # if payoff for deviating strategy is better, remember that fact
    elsif strat_payoff < deviating_profile[0][:payoff]
      one_better = true
    # if payoff for deviating strategy is equal, remember that fact
    elsif strat_payoff == deviating_profile[0][:payoff]
      one_equal = true
    end
  end
  # if made it here, the deviating profile has either all better, or some better and some equal payoffs
  # if all deviation profiles are equal or better, strategy is weakly dominated by the deviation
  return :weakly_dominated if one_equal
  # if all deviating profiles are better, strategy is dominated by the deviation
  return :strictly_dominated if one_better

  raise "nothing better, equal, or worse"
end

#complementary_moves(strategy_profile) ⇒ Object Also known as: other_moves

all other moves other than the passed in strategy (for the player)



226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/minigame/gameable.rb', line 226

def complementary_moves(strategy_profile)
  psp = player_strategy_profiles(strategy_profile[:player])
  psp.select do |x| 
    # not the current strategy
    if x[:strategy] != strategy_profile[:strategy] && 
      # only return profiles matched vs original opposing strategy
      opposing_player_strategy_profile(strategy_profile)[:strategy] == 
        opposing_player_strategy_profile(x)[:strategy]
      true
    else
      false 
    end
  end
end

#deviating_payoffs(strategy_profile) ⇒ Object

all other payoffs other than the passed in strategy (for the player)



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/minigame/gameable.rb', line 242

def deviating_payoffs(strategy_profile)
  psp = player_strategy_profiles(strategy_profile[:player])
  dev_pay = psp.select do |x| 
    # not the current strategy
    if x[:strategy] != strategy_profile[:strategy] && 
      # only payoffs matched with original opposing strategy are
      # considered deviating payoffs
      opposing_player_strategy_profile(strategy_profile)[:strategy] == 
        opposing_player_strategy_profile(x)[:strategy]
      true
    else
      false 
    end
  end
  dev_pay.reduce([]){|acc,p| acc << p}
end

#deviating_strategies(strategy_payoff) ⇒ Object

valid deviations must belong to the same player



106
107
108
# File 'lib/minigame/gameable.rb', line 106

def deviating_strategies(strategy_payoff)
  strategies(strategy_payoff[:player].first).select{|x| x[:name] != strategy_payoff[:strategy][:name]}
end

#equal_moves(strat) ⇒ Object



156
157
158
# File 'lib/minigame/gameable.rb', line 156

def equal_moves(strat)
  complementary_moves(strat).select{|x|x["payoff"]==strat["payoff"]}
end

#nashObject

any set of strategies that are best responses for each other are nash equilibriums



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/minigame/gameable.rb', line 5

def nash
  # assume the same number of strategies for each side for now
  # get one player
  firstp = player_enum.first
  # get opposing player
  opp_p = player_enum[1]
  # get strategies for the player
  pstrats = player_strategy_profiles(firstp)
  oppstrats = player_strategy_profiles(opp_p)
  # loop through first strategies and get best responses
  nash ||=[]
  nash = pstrats.inject([]) do |acc, strat|
    #loop through opposing strategies
    oppstrats.map do |opp_strat|
      br = best_response_against(strat)[:strategy][:name]
      br_opposing = best_response_against(opp_strat)[:strategy][:name]
      # best response for both sides that match each other are nash equilibriums
      if br == opp_strat[:strategy][:name] && br_opposing == strat[:strategy][:name]
        acc << [br,br_opposing]
      end
    end
    acc
  end
  nash.uniq
end

#opposing_player_strategy_profile(strategy_profile) ⇒ Object

returns the strategy associated with the passed in profile belonging to the opposing player



214
215
216
217
218
219
220
221
222
223
# File 'lib/minigame/gameable.rb', line 214

def opposing_player_strategy_profile(strategy_profile)
  # list of players
  # get all strategies profiles for the first player that does not equal
  # the passed in player
  opposing_player = opposing_players(strategy_profile).first
  # return the first strategy with the strategy profile id equal
  # to the passed in strategy profile id
  opposing_strategies = player_strategy_profiles(opposing_player)
  opposing_strategies.select{|x| x[:id]==strategy_profile[:id]}.first
end

#opposing_players(strategy_profile) ⇒ Object



193
194
195
# File 'lib/minigame/gameable.rb', line 193

def opposing_players(strategy_profile)
  players - [strategy_profile[:player].first]
end

#payoff(strategy, player) ⇒ Object



160
161
162
163
# File 'lib/minigame/gameable.rb', line 160

def payoff(strategy, player)
  strategy_profile = [@strategy_profiles.select{|x| x[:strategy]==strategy && x[:player]==player}].flatten.first
  strategy_profile[:payoff] if strategy_profile
end

#player_enumObject



185
186
187
188
189
190
191
# File 'lib/minigame/gameable.rb', line 185

def player_enum
  # need inject to remove duplicates
  player_enums = @strategy_profiles.inject([]) do |acc, x| 
      acc << x[:player] 
  end
  player_enums.uniq
end

#player_from_strategy(strategy) ⇒ Object

retrieve a player assigned to the strategy



100
101
102
103
# File 'lib/minigame/gameable.rb', line 100

def player_from_strategy(strategy)
  stratp = strategy_profiles.detect{|x| x[:strategy][:name] == strategy[:name]}
  stratp[:player] 
end

#player_namesObject



165
166
167
168
169
# File 'lib/minigame/gameable.rb', line 165

def player_names
  players.inject([]) do |acc, x|
    acc << x[:name]
  end 
end

#player_strategy_profiles(player) ⇒ Object



197
198
199
200
201
202
203
204
205
206
# File 'lib/minigame/gameable.rb', line 197

def player_strategy_profiles(player)
  # find some way to standardize what a player is ...
  # possibly plural is enumerable, singular is a hash
  # same problem with other classes
  if player.class == Player
    @strategy_profiles.select{|x| x[:player] == player}
  else
    @strategy_profiles.select{|x| x[:player].first == player}
  end
end

#playersObject



171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/minigame/gameable.rb', line 171

def players
  # need inject to remove duplicates
  @strategy_profiles.inject([]) do |acc, x| 
    if acc.nil? || acc.empty?
      # should be only one player per strategy_profile
      acc << x[:player].first 
    elsif !acc.include?(x[:player].first)
      acc << x[:player].first 
    else
      acc
    end
  end
end

#strategies(player) ⇒ Object



208
209
210
# File 'lib/minigame/gameable.rb', line 208

def strategies(player)
  player_strategy_profiles(player).reduce([]){|acc,strat| acc << strat[:strategy]}.uniq 
end

#strategies_by_player(player) ⇒ Object



88
89
90
91
92
93
94
95
96
97
# File 'lib/minigame/gameable.rb', line 88

def strategies_by_player(player)
  strats = strategy_profiles.inject([]) do |acc, strat| 
    if strat[:player] == player
      acc << strat[:strategy]
    else
      acc
    end
  end
  strats.uniq
end

#strictly_dominated_listObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/minigame/gameable.rb', line 50

def strictly_dominated_list
  dominated_list ||=[]
  players.each do |player|
    dominated_list << player_strategy_profiles(player).inject([]) do |acc, strat|
      # if count of total strategies for opposing player = count of better payoffs, then current strategy is strictly dominated
      dev = deviating_strategies(strat)
      new_strat_list =[]
      dev.each do |dev_strat|
        if compare_deviating_strategy(strat[:strategy], dev_strat) == :strictly_dominated  
          new_strat_list << strat[:strategy] 
        end
      end
      acc << new_strat_list
    end
  end
  dominated_list.flatten.uniq
end

#valid_deviation?(strategy, deviation) ⇒ Boolean

valid deviations must belong to the same player

Returns:

  • (Boolean)


111
112
113
114
# File 'lib/minigame/gameable.rb', line 111

def valid_deviation?(strategy, deviation)
  selected_profile_list = self.strategy_profiles.detect{|x| x[:strategy][:name] == strategy[:name]}
  matching_strategy_deviation = self.strategy_profiles.detect{|x| x[:strategy][:name] == deviation[:name] && x[:player] == selected_profile_list[:player] }
end

#weakly_dominated_listObject



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/minigame/gameable.rb', line 68

def weakly_dominated_list
  dominated_list ||=[]
  players.each do |player|
    dominated_list << player_strategy_profiles(player).inject([]) do |acc, strat|
      dev = deviating_strategies(strat)
      dev.each do |dev_strat|
        if compare_deviating_strategy(strat[:strategy], dev_strat) == :weakly_dominated          
          acc << strat[:strategy] 
        else
          acc
        end
      end
    end
  end
  dom = dominated_list.flatten.uniq
  strict = strictly_dominated_list
  weakly_dominated_list = dom.take_while{|i| strict.include?(i)==false}
  weakly_dominated_list
end

#worse_payoffs?(strategy_profile) ⇒ Boolean

Returns:

  • (Boolean)


272
273
274
# File 'lib/minigame/gameable.rb', line 272

def worse_payoffs?(strategy_profile)
  deviating_payoffs(strategy_profile).select{|x| x[:payoff] < strategy_profile[:payoff]}
end