X-Git-Url: http://git.sourceforge.jp/view?p=shogi-server%2Fshogi-server.git;a=blobdiff_plain;f=shogi_server%2Fpairing.rb;h=6a660ecf06228c0d2ce62ad8de5aa6fbf6a955a2;hp=26d0f9f225006800c12007abcb0e5aea3c424369;hb=667a321f5d24db2988534d6c5bbfb4a015bbe10d;hpb=cad7f2952de01a49b48a4fb4ea40cdf70a469011 diff --git a/shogi_server/pairing.rb b/shogi_server/pairing.rb index 26d0f9f..6a660ec 100644 --- a/shogi_server/pairing.rb +++ b/shogi_server/pairing.rb @@ -1,7 +1,7 @@ ## $Id$ ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch) -## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org) +## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org) ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -33,7 +33,7 @@ module ShogiServer ExcludeSacrificeGps500.new, MakeEven.new, SortByRateWithRandomness.new(1200, 2400), - StartGame.new] + StartGameWithoutHumans.new] end def random_pairing @@ -41,16 +41,15 @@ module ShogiServer ExcludeSacrificeGps500.new, MakeEven.new, Randomize.new, - StartGame.new] + StartGameWithoutHumans.new] end def swiss_pairing - history = ShogiServer::League::Floodgate::History.factory return [LogPlayers.new, ExcludeSacrificeGps500.new, MakeEven.new, - Swiss.new(history), - StartGame.new] + Swiss.new, + StartGameWithoutHumans.new] end def match(players) @@ -65,6 +64,7 @@ module ShogiServer def match(players) # to be implemented + log_message("Floodgate: %s" % [self.class.to_s]) end def include_newbie?(players) @@ -89,7 +89,7 @@ module ShogiServer end end if str_array.empty? - log_message("Floodgate: [Players] None is here.") + log_message("Floodgate: [Players] Nobody found.") else log_message("Floodgate: [Players] %s." % [str_array.join(", ")]) end @@ -99,35 +99,115 @@ module ShogiServer class LogPlayers < Pairing def match(players) + super log_players(players) end end - class StartGame < Pairing + class AbstractStartGame < Pairing + def start_game(p1, p2) + 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.initial + Game.new(p1.game_name, p1, p2, board) + end + + def start_game_shuffle(pair) + pair.shuffle! + start_game(pair.first, pair.last) + end + end + + class StartGame < AbstractStartGame def match(players) super if players.size < 2 - log_warning("Floodgate: There should be more than one player: %d" % [players.size]) + log_warning("Floodgate: There should be more than one player (%d)." % [players.size]) return end if players.size.odd? - log_warning("Floodgate: There are odd players: %d. %s will not be matched." % + log_warning("Floodgate: There are odd players (%d). %s will not be matched." % [players.size, players.last.name]) end log_players(players) while (players.size >= 2) do pair = players.shift(2) - pair.shuffle! - start_game(pair.first, pair.last) + start_game_shuffle(pair) end end + end - def start_game(p1, p2) - log_message("Floodgate: BLACK %s; WHITE %s" % [p1.name, p2.name]) - p1.sente = true - p2.sente = false - Game.new(p1.game_name, p1, p2) + # This tries to avoid a human-human match + # + class StartGameWithoutHumans < AbstractStartGame + def match(players) + super + log_players(players) + if players.size < 2 + log_warning("Floodgate: There should be more than one player (%d)." % [players.size]) + return + elsif players.size == 2 + start_game_shuffle(players) + return + end + + loop do + humans = get_human_indexes(players) + log_message("Floodgate: There are (still) %d humans." % [humans.size]) + break if humans.size < 2 + + pairing_possible = false + for i in 0..(humans.size-2) # -2 + next if humans[i].odd? + if humans[i]+1 == humans[i+1] + pairing_possible = i + break + end + end + unless pairing_possible + log_message("Floodgate: No possible human-human match found") + break + end + + current_index = pairing_possible + j = (current_index == 0 ? current_index : current_index-1) + while j < players.size + break if players[j].is_computer? + j += 1 + end + + pairing_indexes = [] + if j == players.size + # no computer player found + pairing_indexes << current_index << current_index+1 + else + # a comupter player found + pairing_indexes << current_index << j + end + + pair = [] + pair << players.delete_at(pairing_indexes.max) + pair << players.delete_at(pairing_indexes.min) + start_game_shuffle(pair) + end # loop + + while (players.size >= 2) do + pair = players.shift(2) + start_game_shuffle(pair) + end + end + + private + + def get_human_indexes(players) + ret = [] + for i in 0..(players.size-1) + ret << i if players[i].is_human? + end + return ret end end @@ -170,25 +250,29 @@ module ShogiServer end class Swiss < Pairing - def initialize(history) - super() - @history = history - end - def match(players) super - winners = players.find_all {|pl| @history.last_win?(pl.player_id)} - rest = players - winners + if players.size < 3 + log_message("Floodgate: players are small enough to skip Swiss pairing: %d" % [players.size]) + return + end + + path = ShogiServer::League::Floodgate.history_file_path(players.first.game_name) + history = ShogiServer::League::Floodgate::History.factory(path) + + winners = [] + if history + winners = players.find_all {|pl| history.last_win?(pl.player_id)} + end + rest = players - winners - log_message("Floodgate: %d winners" % [winners.size]) + log_message("Floodgate: Ordering %d winners..." % [winners.size]) sbrwr_winners = SortByRateWithRandomness.new(800, 2500) sbrwr_winners.match(winners, true) - log_players(winners) - log_message("Floodgate: and the rest: %d" % [rest.size]) + log_message("Floodgate: Ordering the rest (%d)..." % [rest.size]) sbrwr_losers = SortByRateWithRandomness.new(200, 400) sbrwr_losers.match(rest, true) - log_players(rest) players.clear [winners, rest].each do |group| @@ -201,7 +285,7 @@ module ShogiServer def match(players) super return if less_than_one?(players) - one = players.choice + one = players.sample log_message("Floodgate: Deleted %s at random" % [one.name]) players.delete(one) log_players(players) @@ -274,7 +358,7 @@ module ShogiServer def match(players) super return if players.size.even? - log_message("Floodgate: there are odd players: %d. Deleting one..." % + log_message("Floodgate: There are odd players (%d). Deleting one of them..." % [players.size]) DeletePlayerAtRandom.new.match(players) end