+require 'thread'
+require 'ostruct'
+require 'pathname'
+
module ShogiServer
class League
class Floodgate
class << self
+ # "floodgate-900-0"
+ #
def game_name?(str)
- return /^floodgate-\d+-\d+$/.match(str) ? true : false
+ return /^floodgate\-\d+\-\d+$/.match(str) ? true : false
end
end
- def initialize(league)
+ attr_reader :next_time, :league
+
+ def initialize(league, next_time=nil)
@league = league
- @next_time = nil
+ @next_time = next_time
charge
end
- def run
- @thread = Thread.new do
- Thread.pass
- while (true)
- begin
- sleep(10)
- next if Time.now < @next_time
- @league.reload
- match_game
- charge
- rescue Exception => ex
- # ignore errors
- log_error("[in Floodgate's thread] #{ex} #{ex.backtrace}")
- end
- end
- end
- end
-
- def shutdown
- @thread.kill if @thread
- end
-
- # private
-
def charge
now = Time.now
- # if now.min < 30
- # @next_time = Time.mktime(now.year, now.month, now.day, now.hour, 30)
- # else
- # @next_time = Time.mktime(now.year, now.month, now.day, now.hour) + 3600
- # end
- # for test
- if now.sec < 30
- @next_time = Time.mktime(now.year, now.month, now.day, now.hour, now.min, 30)
+ unless $DEBUG
+ # each 30 minutes
+ if now.min < 30
+ @next_time = Time.mktime(now.year, now.month, now.day, now.hour, 30)
+ else
+ @next_time = Time.mktime(now.year, now.month, now.day, now.hour) + 3600
+ end
else
- @next_time = Time.mktime(now.year, now.month, now.day, now.hour, now.min) + 60
+ # for test, each 30 seconds
+ if now.sec < 30
+ @next_time = Time.mktime(now.year, now.month, now.day, now.hour, now.min, 30)
+ else
+ @next_time = Time.mktime(now.year, now.month, now.day, now.hour, now.min) + 60
+ end
end
end
Floodgate.game_name?(pl.game_name) &&
pl.sente == nil
end
- #log_warning("DEBUG: %s" % [File.join(File.dirname(__FILE__), "pairing.rb")])
- #load File.join(File.dirname(__FILE__), "pairing.rb")
- Pairing.default_pairing.match(players)
+ Pairing.match(players)
end
+
+
+ #
+ #
+ class History
+ @@mutex = Mutex.new
+
+ class << self
+ def factory
+ file = Pathname.new $options["floodgate-history"]
+ history = History.new file
+ history.load
+ return history
+ end
+ end
+
+ attr_reader :records
+
+ # file_path_name is a Pathname object for this storage
+ #
+ def initialize(file_path_name)
+ @records = []
+ @max_records = 100
+ @file = file_path_name
+ end
+
+ # Return a hash describing the game_result
+ # :game_id: game id
+ # :black: Black's player id
+ # :white: White's player id
+ # :winner: Winner's player id or nil for the game without a winner
+ # :loser: Loser's player id or nil for the game without a loser
+ #
+ def make_record(game_result)
+ hash = Hash.new
+ hash[:game_id] = game_result.game.game_id
+ hash[:black] = game_result.black.player_id
+ hash[:white] = game_result.white.player_id
+ case game_result
+ when GameResultWin
+ hash[:winner] = game_result.winner.player_id
+ hash[:loser] = game_result.loser.player_id
+ else
+ hash[:winner] = nil
+ hash[:loser] = nil
+ end
+ return hash
+ end
+
+ def load
+ return unless @file.exist?
+
+ @records = YAML.load_file(@file)
+ unless @records && @records.instance_of?(Array)
+ $logger.error "%s is not a valid yaml file. Instead, an empty array will be used and updated." % [@file]
+ @records = [].to_yaml
+ end
+ end
+
+ def save
+ begin
+ @file.open("w") do |f|
+ f << YAML.dump(@records)
+ end
+ rescue Errno::ENOSPC
+ # ignore
+ end
+ end
+
+ def update(game_result)
+ record = make_record(game_result)
+ @@mutex.synchronize do
+ load
+ @records << record
+ while @records.size > @max_records
+ @records.shift
+ end
+ save
+ end
+ end
+
+ def last_win?(player_id)
+ rc = last_valid_game(player_id)
+ return false unless rc
+ return rc[:winner] == player_id
+ end
+
+ def last_lose?(player_id)
+ rc = last_valid_game(player_id)
+ return false unless rc
+ return rc[:loser] == player_id
+ end
+
+ def last_valid_game(player_id)
+ records = nil
+ @@mutex.synchronize do
+ records = @records.reverse
+ end
+ rc = records.find do |rc|
+ rc[:winner] &&
+ rc[:loser] &&
+ (rc[:black] == player_id || rc[:white] == player_id)
+ end
+ return rc
+ end
+ end # class History
+
+
end # class Floodgate
+
end # class League
end # module ShogiServer