OSDN Git Service

- shogi-server, shogi_server/league/floodgate.rb: Changed the argument of Floodgate...
[shogi-server/shogi-server.git] / shogi_server / league / floodgate.rb
index 5f91057..4f6ac2b 100644 (file)
+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, hash={})
       @league = league
-      @next_time = nil
+      @next_time = hash[:next_time] || nil
+      @game_name = hash[:game_name] || "floodgate-900-0"
       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
+    def game_name?(str)
+      return Regexp.new(@game_name).match(str) ? true : false
     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
 
     def match_game
       players = @league.find_all_players do |pl|
         pl.status == "game_waiting" &&
-        Floodgate.game_name?(pl.game_name) &&
+        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
+
+      # Initialize this instance.
+      # @param file_path_name 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 = []
+        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