OSDN Git Service

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