OSDN Git Service

Merge branch 'wdoor-stable'
[shogi-server/shogi-server.git] / test / baseclient.rb
1 require 'socket'
2 require 'stringio'
3 require 'thread'
4 require 'test/unit'
5
6 class SocketPlayer
7   def initialize(game_name, name, sente)
8     @game_name = game_name
9     @name = "%s_%s" % [game_name, name]
10     if sente == "*"
11       @turn_mark = sente
12     else
13       @turn_mark = sente ? "+" : "-"
14     end
15     @received_moves = 0
16     @socket = nil
17     @message = ""
18     @mutex = Mutex.new
19     @login_command = "LOGIN #{@name} dummy x1"
20   end
21   attr_reader :message
22   attr_accessor :login_command
23
24   def connect
25     port = 4000
26     @socket = TCPSocket.open("localhost", port)
27     @socket.sync = true
28     @message = ""
29     reader
30   end
31
32   def close
33     @socket.close if @socket && !@socket.closed?
34   end
35
36   def reader
37     @thread = Thread.new do
38       begin
39         Thread.pass
40         loop do 
41           break if @socket.closed?
42           if r = select([@socket], nil, nil, 10)
43             str = r[0].first.gets
44             break if str.nil?
45             @mutex.synchronize do
46               if %r!^[\+\-]\d{4}\w{2},T\d+$! =~ str
47                   @received_moves += 1
48               end
49               @message << str
50             end
51           else
52             raise "timed out"
53           end
54         end
55       rescue IOError
56         $stderr.puts "\nReader thread interrupted"
57       end
58     end
59   end
60
61   def stop_reader
62     @thread.kill if @thread
63   end
64
65   def wait(reg)
66     loop do 
67       @mutex.synchronize do
68         return if reg =~ @message
69       end
70       sleep 0.01
71     end
72   end
73
74   def wait_nmoves(n)
75     loop do
76       @mutex.synchronize do
77         return if @received_moves == n
78       end
79       sleep 0.01
80     end
81   end
82
83   def login
84     str = @login_command
85     $stderr.puts str if $DEBUG
86     @socket.puts str
87     wait %r!^LOGIN!
88   end
89
90   def game
91     str = "%%GAME #{@game_name}-1500-0 #{@turn_mark}"
92     $stderr.puts str if $DEBUG
93     @socket.puts str
94   end
95
96   def challenge
97     str = "%%CHALLENGE #{@game_name}-1500-0 #{@turn_mark}"
98     $stderr.puts str if $DEBUG
99     @socket.puts str
100   end
101
102   def wait_game
103     wait %r!^END Game_Summary!
104   end
105
106   def agree
107     @socket.puts "AGREE"
108   end
109
110   def wait_agree
111     wait %r!^START:!
112   end
113
114   def move(m)
115     @socket.puts m
116   end
117   def puts(m)
118     @socket.puts m
119   end
120
121   def toryo
122     @socket.puts "%TORYO"
123   end
124
125   def wait_finish
126     wait %r!^#(WIN|LOSE)!
127   end
128
129   def logout
130     @socket.puts "LOGOUT"
131     @socket.close
132   end
133
134 end
135
136 class SocketCSAPlayer < SocketPlayer
137   def initialize(game_name, name, sente)
138     super
139     @login_command = "LOGIN #{@name} dummy"
140   end
141
142   def login
143     str = @login_command
144     $stderr.puts str if $DEBUG
145     @socket.puts str
146     wait %r!^LOGIN!
147   end
148 end
149
150
151
152
153
154 class BaseClient < Test::Unit::TestCase
155   attr_accessor :game_name, :p1_name, :p2_name
156
157   def set_name
158     @game_name = self.class.name
159     @p1_name = "sente"
160     @p2_name = "gote"
161   end
162
163   def set_player
164     @p1 = SocketPlayer.new @game_name, @p1_name, true
165     @p2 = SocketPlayer.new @game_name, @p2_name, false
166   end
167
168   def setup
169     set_name
170     set_player
171     @nmoves = 0
172   end
173   attr_reader :src1, :src2
174
175   def teardown
176     @p1.close
177     @p2.close
178   end
179
180   def test_dummy
181     assert true
182   end
183
184   def login
185     @p1.connect
186     @p2.connect
187     @p1.login
188     @p2.login
189     @p1.game
190     @p2.game
191     @p1.wait_game
192     @p2.wait_game
193   end
194
195   def agree
196     @p1.agree
197     @p2.agree
198     @p1.wait_agree
199     @p2.wait_agree
200   end
201
202   def handshake
203     login
204     agree
205
206     move "+2726FU"
207     move "-3334FU"
208    
209     yield if block_given?
210
211     logout12
212     [@p1.message, @p2.message]
213   end
214
215   def move(m)
216     case m
217     when /^\+/
218       move1(m)
219     when /^\-/
220       move2(m)
221     else
222       raise "do not reach!"
223     end
224   end
225
226   def move1(m)
227     @p1.move m
228     @nmoves += 1
229     @p2.wait_nmoves @nmoves
230   end
231
232   def move2(m)
233     @p2.move m
234     @nmoves += 1
235     @p1.wait_nmoves @nmoves
236   end
237
238   def cmd(s)
239     @p1.move s
240     return @p1.message
241   end
242
243   def cmd2(s)
244     @p2.move s
245     return @p2.message
246   end
247
248   def wait_finish
249     @p1.wait_finish
250     @p2.wait_finish
251   end
252
253   def logout12
254     @p1.logout
255     @p2.logout
256   end
257
258   def logout21
259     @p2.logout
260     @p1.logout
261   end
262
263 end
264
265
266 class ReadFileClient < BaseClient
267   def filepath(csa_file_name)
268     return File.join(File.dirname(__FILE__), "csa", csa_file_name)
269   end
270
271   def handshake(csa)
272     login
273     agree
274
275     csa_io = StringIO.new(csa)
276     while line = csa_io.gets do
277       case line
278       when /^[\+\-]\d{4}\w{2}/
279         s = $&
280         $stderr.puts s if $DEBUG
281         move s
282       end
283     end
284   end
285 end # ReadFileClient
286
287
288 class CSABaseClient < BaseClient
289   ##
290   # In CSA mode, the server decides sente or gote at random; and sockets are closed
291   # just after the game ends (i.e. %TORYO is sent)
292   # 
293   def set_player
294     @p1 = SocketCSAPlayer.new @game_name, @p1_name, true
295     @p2 = SocketCSAPlayer.new @game_name, @p2_name, false
296   end
297
298   def teardown
299     @p1.stop_reader
300     @p2.stop_reader
301     super
302   end
303
304   def handshake
305     @p1.connect
306     @p2.connect
307     @p1.login
308     @p2.login
309     agree
310
311     if /Your_Turn:\+/ =~ @p1.message
312     else
313       @p1,@p2 = @p2,@p1
314     end
315
316     move "+7776FU"
317     move "-3334FU"
318     yield if block_given?
319     
320     [@p1.message, @p2.message]
321   end
322
323 end # CSABaseClient
324
325