OSDN Git Service

Record Floodgate games' history
[shogi-server/shogi-server.git] / shogi_server / league / floodgate.rb
1 require 'thread'
2 require 'ostruct'
3 require 'pathname'
4
5 module ShogiServer
6
7 class League
8   class Floodgate
9     class << self
10       def game_name?(str)
11         return /^floodgate-\d+-\d+$/.match(str) ? true : false
12       end
13     end
14
15     attr_reader :next_time, :league
16
17     def initialize(league, next_time=nil)
18       @league = league
19       @next_time = next_time
20       charge
21     end
22
23     def charge
24       now = Time.now
25       unless $DEBUG
26         # each 30 minutes
27         if now.min < 30
28           @next_time = Time.mktime(now.year, now.month, now.day, now.hour, 30)
29         else
30           @next_time = Time.mktime(now.year, now.month, now.day, now.hour) + 3600
31         end
32       else
33         # for test, each 30 seconds
34         if now.sec < 30
35           @next_time = Time.mktime(now.year, now.month, now.day, now.hour, now.min, 30)
36         else
37           @next_time = Time.mktime(now.year, now.month, now.day, now.hour, now.min) + 60
38         end
39       end
40     end
41
42     def match_game
43       players = @league.find_all_players do |pl|
44         pl.status == "game_waiting" &&
45         Floodgate.game_name?(pl.game_name) &&
46         pl.sente == nil
47       end
48       Pairing.match(players)
49     end
50
51
52     #
53     #
54     class History
55       @@mutex = Mutex.new
56
57       class << self
58         def factory
59           file = Pathname.new $options["floodgate-history"]
60           return History.new file
61         end
62       end
63
64       # file_path_name is a Pathname object for this storage
65       #
66       def initialize(file_path_name)
67         @records = []
68         @max_records = 100
69         @file = file_path_name
70       end
71
72       # Return a hash describing the game_result
73       # :game_id: game id
74       # :black:   Black's player id
75       # :white:   White's player id
76       # :winner:  Winner's player id or nil for the game without a winner
77       # :loser:   Loser's player id or nil for the game without a loser
78       #
79       def make_record(game_result)
80         hash = Hash.new
81         hash[:game_id] = game_result.game.game_id
82         hash[:black]   = game_result.black.player_id
83         hash[:white]   = game_result.white.player_id
84         case game_result
85         when GameResultWin
86           hash[:winner] = game_result.winner.player_id
87           hash[:loser]  = game_result.loser.player_id
88         else
89           hash[:winner] = nil
90           hash[:loser]  = nil
91         end
92         return hash
93       end
94
95       def load
96         return unless @file.exist?
97
98         yaml = @file.open("r") {|f| f.read}
99         @records = YAML.load(yaml)
100       end
101
102       def save
103         begin
104           @file.open("w+") do |f| 
105             f << YAML.dump(@records)
106           end
107         rescue Errno::ENOSPC
108           # ignore
109         end
110       end
111
112       def update(game_result)
113         record = make_record(game_result)
114         @@mutex.synchronize do 
115           load
116           @records << record
117           while @records.size > @max_records
118             @records.shift
119           end
120           save
121         end
122       end
123       
124       def last_win?(player_id)
125         rc = last_valid_record(player_id)
126         return false unless rc
127         return rc[:winner] == player_id
128       end
129       
130       def last_lose?(player_id)
131         rc = last_valid_record(player_id)
132         return false unless rc
133         return rc[:loser] == player_id
134       end
135
136       def last_valid_record(player_id)
137         records = nil
138         @mutex.synchronize do
139           records = @records.reverse
140         end
141         rc = records.find do |rc|
142           rc[:winner] && 
143           rc[:loser]  && 
144           (rc[:black] == player_id || rc[:while] == player_id)
145         end
146         return rc
147       end
148     end # class History
149
150
151   end # class Floodgate
152
153
154 end # class League
155 end # module ShogiServer