class Pairing
class << self
- def default_factory
- return least_diff_pairing
+ def default_factory(options)
+ return least_diff_pairing(options)
end
- def sort_by_rate_with_randomness
+ def sort_by_rate_with_randomness(options)
return [LogPlayers.new,
- ExcludeSacrificeGps500.new,
+ ExcludeSacrifice.new(options[:sacrifice]),
MakeEven.new,
SortByRateWithRandomness.new(1200, 2400),
StartGameWithoutHumans.new]
end
- def random_pairing
+ def random_pairing(options)
return [LogPlayers.new,
- ExcludeSacrificeGps500.new,
+ ExcludeSacrifice.new(options[:sacrifice]),
MakeEven.new,
Randomize.new,
StartGameWithoutHumans.new]
end
- def swiss_pairing
+ def swiss_pairing(options)
return [LogPlayers.new,
- ExcludeSacrificeGps500.new,
+ ExcludeSacrifice.new(options[:sacrifice]),
MakeEven.new,
Swiss.new,
StartGameWithoutHumans.new]
end
- def least_diff_pairing
+ def least_diff_pairing(options)
return [LogPlayers.new,
- ExcludeSacrificeGps500.new,
+ ExcludeSacrifice.new(options[:sacrifice]),
MakeEven.new,
LeastDiff.new,
StartGameWithoutHumans.new]
end
- def floodgate_zyunisen
+ def floodgate_zyunisen(options)
return [LogPlayers.new,
ExcludeUnratedPlayers.new,
- ExcludeSacrificeGps500.new,
+ ExcludeSacrifice.new(options[:sacrifice]),
MakeEven.new,
LeastDiff.new,
StartGameWithoutHumans.new]
end
- def match(players, logics)
+ def match(players, logics, options)
logics.inject(players) do |result, item|
+ item.set_options(options)
item.match(result)
result
end
end
end # class << self
+ def initialize
+ @options = {}
+ end
+
+ def set_options(options)
+ @options.merge!(options)
+ end
# Make matches among players.
# @param players an array of players, which should be updated destructively
log_message("Floodgate: Starting a game: BLACK %s vs WHITE %s" % [p1.name, p2.name])
p1.sente = true
p2.sente = false
- board = Board.new
+ board = Board.new(@options)
board.initial
Game.new(p1.game_name, p1, p2, board)
end
def match(players)
super
if players.size < 2
- log_warning("Floodgate: There should be more than one player (%d)." % [players.size])
+ log_message("Floodgate: There are less than two players: %d" % [players.size])
return
end
if players.size.odd?
super
log_players(players)
if players.size < 2
- log_warning("Floodgate: There should be more than one player (%d)." % [players.size])
+ log_message("Floodgate: There are less than two players: %d" % [players.size])
return
elsif players.size == 2
start_game_shuffle(players)
# @sacrifice a player id to be eliminated
def initialize(sacrifice)
super()
- @sacrifice = sacrifice
+ @sacrifice = sacrifice || "gps500+e293220e3f8a3e59f79f6b0efffaa931"
end
def match(players)
if p1.is_human? && p2.is_human?
ret += 800
end
+
+ # 2.3 a match with likely kin players
+ if (p1.player_id[0..6] == p2.player_id[0..6])
+ ret += 800
+ elsif (p1.player_id[0..3] == p2.player_id[0..3])
+ ret += 400
+ end
end
ret
end
+ # Total combinations of possible games among n players
+ # nC2 * (n-2)C2 * ... * 2C2 / (n/2)!
+ def total_posibilities(n)
+ n -= 1 if n.odd?
+ return 1 if n <= 2
+
+ ret = 1
+ i = n
+ while i >= 2 do
+ ret *= ::ShogiServer::nCk(i,2)
+ i -= 2
+ end
+ ret /= ::ShogiServer::factorial(n/2)
+ return ret
+ end
+
def match(players)
super
if players.size < 3
# Reset estimated rate
players.each {|p| p.estimated_rate = 0}
- # 10 trials
matches = []
scores = []
path = ShogiServer::League::Floodgate.history_file_path(players.first.game_name)
history = ShogiServer::League::Floodgate::History.factory(path)
- 10.times do
+
+ # Increase trials, depending on a number of players
+ trials = [300, total_posibilities(players.size)/3].min
+ trials = [10, trials].max
+ log_message("Floodgate: %d trials" % [trials])
+ trials.times do
m = random_match(players)
matches << m
scores << calculate_diff_with_penalty(m, history)
min_score = s
end
end
- log_message("Floodgate: the least score %d (%d per player) [%s]" % [min_score, min_score/players.size, scores.join(" ")])
+ log_message("Floodgate: the least score %d (%d per game) [%s]" % [min_score, min_score/players.size*2, scores.join(" ")])
players.replace(matches[min_index])
end