1 require 'shogi_server/util'
12 # ex. "floodgate-900-0"
15 return /^floodgate\-\d+\-\d+$/.match(str) ? true : false
18 def history_file_path(gamename)
19 return nil unless game_name?(gamename)
20 filename = "floodgate_history_%s.yaml" % [gamename.gsub("floodgate-", "").gsub("-","_")]
21 file = File.join($topdir, filename)
22 return Pathname.new(file)
26 # @next_time is updated if and only if charge() was called
28 attr_reader :next_time
29 attr_reader :league, :game_name
31 def initialize(league, hash={})
33 @next_time = hash[:next_time] || nil
34 @game_name = hash[:game_name] || "floodgate-900-0"
35 charge if @next_time.nil?
39 return Regexp.new(@game_name).match(str) ? true : false
43 ntg = NextTimeGenerator.factory(@game_name)
45 @next_time = ntg.call(Time.now)
52 players = @league.find_all_players do |pl|
53 pl.status == "game_waiting" &&
54 game_name?(pl.game_name) &&
57 Pairing.match(players)
62 class NextTimeGenerator
64 def factory(game_name)
66 conf_file_name = File.join($topdir, "#{game_name}.conf")
69 ret = NextTimeGenerator_Debug.new
70 elsif File.exists?(conf_file_name)
71 lines = IO.readlines(conf_file_name)
72 ret = NextTimeGeneratorConfig.new(lines)
73 elsif game_name == "floodgate-900-0"
74 ret = NextTimeGenerator_Floodgate_900_0.new
75 elsif game_name == "floodgate-3600-0"
76 ret = NextTimeGenerator_Floodgate_3600_0.new
83 # Schedule the next time from configuration files.
86 # # This is a comment line
90 # DoW := "Sun" | "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" |
91 # "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" |
92 # "Friday" | "Saturday"
100 class NextTimeGeneratorConfig
103 # Read configuration contents.
105 def initialize(lines)
109 def call(now=Time.now)
110 if now.kind_of?(Time)
111 now = ::ShogiServer::time2datetime(now)
115 # now.cwday 1(Monday)-7
116 @lines.each do |line|
117 if %r!^\s*(\w+)\s+(\d{1,2}):(\d{1,2})! =~ line
118 dow, hour, minute = $1, $2.to_i, $3.to_i
119 dow_index = ::ShogiServer::parse_dow(dow)
120 next if dow_index.nil?
121 next unless (0..23).include?(hour)
122 next unless (0..59).include?(minute)
123 time = DateTime::commercial(now.cwyear, now.cweek, dow_index, hour, minute) rescue next
124 time += 7 if time <= now
128 candidates.map! {|dt| ::ShogiServer::datetime2time(dt)}
129 return candidates.empty? ? nil : candidates.min
133 # Schedule the next time for floodgate-900-0: each 30 minutes
135 class NextTimeGenerator_Floodgate_900_0
138 return Time.mktime(now.year, now.month, now.day, now.hour, 30)
140 return Time.mktime(now.year, now.month, now.day, now.hour) + 3600
145 # Schedule the next time for floodgate-3600-0: each 2 hours (odd hour)
147 class NextTimeGenerator_Floodgate_3600_0
149 return Time.mktime(now.year, now.month, now.day, now.hour) + ((now.hour%2)+1)*3600
153 # Schedule the next time for debug: each 30 seconds.
155 class NextTimeGenerator_Debug
158 return Time.mktime(now.year, now.month, now.day, now.hour, now.min, 30)
160 return Time.mktime(now.year, now.month, now.day, now.hour, now.min) + 60
171 def factory(pathname)
172 unless ShogiServer::is_writable_file?(pathname.to_s)
173 log_error("Failed to write a history file: %s" % [pathname])
176 history = History.new pathname
184 # Initialize this instance.
185 # @param file_path_name a Pathname object for this storage
187 def initialize(file_path_name)
190 @file = file_path_name
193 # Return a hash describing the game_result
195 # :black: Black's player id
196 # :white: White's player id
197 # :winner: Winner's player id or nil for the game without a winner
198 # :loser: Loser's player id or nil for the game without a loser
200 def make_record(game_result)
202 hash[:game_id] = game_result.game.game_id
203 hash[:black] = game_result.black.player_id
204 hash[:white] = game_result.white.player_id
207 hash[:winner] = game_result.winner.player_id
208 hash[:loser] = game_result.loser.player_id
217 return unless @file.exist?
219 @records = YAML.load_file(@file)
220 unless @records && @records.instance_of?(Array)
221 $logger.error "%s is not a valid yaml file. Instead, an empty array will be used and updated." % [@file]
228 @file.open("w") do |f|
229 f << YAML.dump(@records)
236 def update(game_result)
237 record = make_record(game_result)
238 @@mutex.synchronize do
241 while @records.size > @max_records
248 def last_win?(player_id)
249 rc = last_valid_game(player_id)
250 return false unless rc
251 return rc[:winner] == player_id
254 def last_lose?(player_id)
255 rc = last_valid_game(player_id)
256 return false unless rc
257 return rc[:loser] == player_id
260 def last_valid_game(player_id)
262 @@mutex.synchronize do
263 records = @records.reverse
265 rc = records.find do |rc|
268 (rc[:black] == player_id || rc[:white] == player_id)
275 end # class Floodgate
279 end # module ShogiServer