OSDN Git Service

Debugged 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       attr_reader :records
65
66       # file_path_name is a Pathname object for this storage
67       #
68       def initialize(file_path_name)
69         @records = []
70         @max_records = 100
71         @file = file_path_name
72       end
73
74       # Return a hash describing the game_result
75       # :game_id: game id
76       # :black:   Black's player id
77       # :white:   White's player id
78       # :winner:  Winner's player id or nil for the game without a winner
79       # :loser:   Loser's player id or nil for the game without a loser
80       #
81       def make_record(game_result)
82         hash = Hash.new
83         hash[:game_id] = game_result.game.game_id
84         hash[:black]   = game_result.black.player_id
85         hash[:white]   = game_result.white.player_id
86         case game_result
87         when GameResultWin
88           hash[:winner] = game_result.winner.player_id
89           hash[:loser]  = game_result.loser.player_id
90         else
91           hash[:winner] = nil
92           hash[:loser]  = nil
93         end
94         return hash
95       end
96
97       def load
98         return unless @file.exist?
99
100         yaml = @file.open("r") {|f| f.read}
101         @records = YAML.load(yaml)
102       end
103
104       def save
105         begin
106           @file.open("w+") do |f| 
107             f << YAML.dump(@records)
108           end
109         rescue Errno::ENOSPC
110           # ignore
111         end
112       end
113
114       def update(game_result)
115         record = make_record(game_result)
116         @@mutex.synchronize do 
117           load
118           @records << record
119           while @records.size > @max_records
120             @records.shift
121           end
122           save
123         end
124       end
125       
126       def last_win?(player_id)
127         rc = last_valid_game(player_id)
128         return false unless rc
129         return rc[:winner] == player_id
130       end
131       
132       def last_lose?(player_id)
133         rc = last_valid_game(player_id)
134         return false unless rc
135         return rc[:loser] == player_id
136       end
137
138       def last_valid_game(player_id)
139         records = nil
140         @@mutex.synchronize do
141           records = @records.reverse
142         end
143         rc = records.find do |rc|
144           rc[:winner] && 
145           rc[:loser]  && 
146           (rc[:black] == player_id || rc[:white] == player_id)
147         end
148         return rc
149       end
150     end # class History
151
152
153   end # class Floodgate
154
155
156 end # class League
157 end # module ShogiServer