OSDN Git Service

Debugging Floodgate
[shogi-server/shogi-server.git] / shogi_server / pairing.rb
1 ## $Id$
2
3 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
4 ## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
5 ##
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
10 ##
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ## GNU General Public License for more details.
15 ##
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, write to the Free Software
18 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 require 'shogi_server/util'
21
22 module ShogiServer
23
24   class Pairing
25
26     class << self
27       def default_factory
28         return sort_by_rate_with_randomness
29       end
30
31       def sort_by_rate_with_randomness
32         return [ExcludeSacrificeGps500.new,
33                 MakeEven.new,
34                 SortByRateWithRandomness.new(1200, 2400),
35                 StartGame.new]
36       end
37
38       def random_pairing
39         return [ExcludeSacrificeGps500.new,
40                 MakeEven.new,
41                 Randomize.new,
42                 StartGame.new]
43       end
44
45       def match(players)
46         logics = default_factory
47         logics.inject(players) do |result, item|
48           item.match(result)
49         end
50       end
51     end # class << self
52
53
54     def match(players)
55       # to be implemented
56     end
57
58     def include_newbie?(players)
59       return players.find{|a| a.rate == 0} == nil ? false : true
60     end
61
62     def less_than_one?(players)
63       if players.size < 1
64         log_warning("Floodgate: There should be at least one player.")
65         return true
66       else
67         return false
68       end
69     end
70
71     def log_players(players)
72       str_array = players.map do |one|
73         if block_given?
74           yield one
75         else
76           one.name
77         end
78       end
79       if str_array.empty?
80         log_message("Floodgate: [Players] None is here.")
81       else
82         log_message("Floodgate: [Players] %s." % [str_array.join(", ")])
83       end
84     end
85   end # Pairing
86
87   class StartGame < Pairing
88     def match(players)
89       super
90       if players.size < 2
91         log_warning("Floodgate: There should be more than one player: %d" % [players.size])
92         return
93       end
94       if players.size.odd?
95         log_warning("Floodgate: There are odd players: %d. %s will not be matched." % 
96                     [players.size, players.last.name])
97       end
98
99       log_players(players)
100       while (players.size >= 2) do
101         pair = players.shift(2)
102         pair.shuffle!
103         start_game(pair.first, pair.last)
104       end
105     end
106
107     def start_game
108       log_message("Floodgate: BLACK %s; WHITE %s" % [p1.name, p2.name])
109       p1.sente = true
110       p2.sente = false
111       Game.new(p1.game_name, p1, p2)
112     end
113   end
114
115   class Randomize < Pairing
116     def match(players)
117       super
118       log_message("Floodgate: Randomize... before")
119       log_players(players)
120       players.shuffle!
121       log_message("Floodgate: Randomized after")
122       log_players(players)
123     end
124   end # RadomPairing
125
126   class SortByRate < Pairing
127     def match(players)
128       super
129       log_message("Floodgate: Ordered by rate")
130       players.sort! {|a,b| a.rate <=> b.rate} # decendent order
131       log_players(players)
132     end
133   end
134
135   class SortByRateWithRandomness < Pairing
136     def initialize(rand1, rand2)
137       super()
138       @rand1, @rand2 = rand1, rand2
139     end
140
141     def match(players)
142       super
143       cur_rate = Hash.new
144       players.each{|a| cur_rate[a] = a.rate ? a.rate + rand(@rand1) : rand(@rand2)}
145       players.sort!{|a,b| cur_rate[a] <=> cur_rate[b]}
146       log_players(players) do |one|
147         "%s %d (randomness %d)" % [one.name, one.rate, cur_rate[one] - one.rate]
148       end
149     end
150   end
151
152   class DeletePlayerAtRandom < Pairing
153     def match(players)
154       super
155       return if less_than_one?(players)
156       one = players.choice
157       log_message("Floodgate: Deleted %s at random" % [one.name])
158       players.delete(one)
159       log_players(players)
160     end
161   end
162
163   class DeletePlayerAtRandomExcept < Pairing
164     def initialize(except)
165       super()
166       @except = except
167     end
168
169     def match(players)
170       super
171       log_message("Floodgate: Deleting a player at rondom except %s" % [@except.name])
172       players.delete(@except)
173       DeletePlayerAtRandom.new.match(players)
174       players.push(@except)
175     end
176   end
177   
178   class DeleteMostPlayingPlayer < Pairing
179     def match(players)
180       super
181       one = players.max_by {|a| a.win + a.loss}
182       log_message("Floodgate: Deleted the most playing player: %s (%d)" % [one.name, one.win + one.loss])
183       players.delete(one)
184       log_players(players)
185     end
186   end
187
188   class DeleteLeastRatePlayer < Pairing
189     def match(players)
190       super
191       one = players.min_by {|a| a.rate}
192       log_message("Floodgate: Deleted the least rate player %s (%d)" % [one.name, one.rate])
193       players.delete(one)
194       log_players(players)
195     end
196   end
197
198   class ExcludeSacrifice < Pairing
199     attr_reader :sacrifice
200
201     # @sacrifice a player id to be eliminated
202     def initialize(sacrifice)
203       super()
204       @sacrifice = sacrifice
205     end
206
207     def match(players)
208       super
209       if @sacrifice && 
210          players.size.odd? && 
211          players.find{|a| a.player_id == @sacrifice}
212          log_message("Floodgate: Deleting the sacrifice %s" % [@sacrifice])
213          players.delete_if{|a| a.player_id == @sacrifice}
214          log_players(players)
215       end
216     end
217   end # class ExcludeSacrifice
218
219   class ExcludeSacrificeGps500 < ExcludeSacrifice
220     def initialize
221       super("gps500+e293220e3f8a3e59f79f6b0efffaa931")
222     end
223   end
224
225   class MakeEven < Pairing
226     def match(players)
227       super
228       return if players.size.even?
229       log_message("Floodgate: there are odd players: %d. Deleting one..." % 
230                   [players.size])
231       DeletePlayerAtRandom.new.match(players)
232     end
233   end
234
235 end # ShogiServer