OSDN Git Service

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