• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

shogi-server source


Commit MetaInfo

Revisionb0a2884dfa2bde82572e2156a7b6ec142bed51f5 (tree)
Time2015-01-12 21:54:42
AuthorDaigo Moriwaki <daigo@debi...>
CommiterDaigo Moriwaki

Log Message

New feature: Zero least time per move.

New command line option: --least-time-per-move n

Change Summary

Incremental Difference

--- a/changelog
+++ b/changelog
@@ -12,6 +12,11 @@
1212 - A new log summary type, "max_moves_draw", has been assigned for games
1313 drawing with max moves.
1414 'summary:max_moves_draw:name_sente draw:name_gote draw
15+ - Least time per move:
16+ - New command line option: --least-time-per-move n
17+ This opotion specifies a least time in second per move, which
18+ was previously 1 sec but is now by default 1, meaning that a
19+ decimal fraction of time for a move will be truncated.
1520
1621 2014-07-19 Daigo Moriwaki <daigo at debian dot org>
1722
--- a/shogi-server
+++ b/shogi-server
@@ -76,6 +76,10 @@ OPTIONS
7676 port_number
7777 a port number for the server to listen.
7878 4081 is often used.
79+ --least-time-per-move n
80+ Least time in second per move: 0, 1 (default 1).
81+ - 0: The new rule that CSA introduced in November 2014.
82+ - 1: The old rule before it.
7983 --max-moves n
8084 when a game with the n-th move played does not end, make the game a draw.
8185 Default 256. 0 disables this feature.
@@ -194,11 +198,12 @@ end
194198 def parse_command_line
195199 options = Hash::new
196200 parser = GetoptLong.new(
197- ["--daemon", GetoptLong::REQUIRED_ARGUMENT],
198- ["--floodgate-games", GetoptLong::REQUIRED_ARGUMENT],
199- ["--max-moves", GetoptLong::REQUIRED_ARGUMENT],
200- ["--pid-file", GetoptLong::REQUIRED_ARGUMENT],
201- ["--player-log-dir", GetoptLong::REQUIRED_ARGUMENT])
201+ ["--daemon", GetoptLong::REQUIRED_ARGUMENT],
202+ ["--floodgate-games", GetoptLong::REQUIRED_ARGUMENT],
203+ ["--least-time-per-move", GetoptLong::REQUIRED_ARGUMENT],
204+ ["--max-moves", GetoptLong::REQUIRED_ARGUMENT],
205+ ["--pid-file", GetoptLong::REQUIRED_ARGUMENT],
206+ ["--player-log-dir", GetoptLong::REQUIRED_ARGUMENT])
202207 parser.quiet = true
203208 begin
204209 parser.each_option do |name, arg|
@@ -270,6 +275,9 @@ def check_command_line
270275
271276 $options["max-moves"] ||= 256
272277 $options["max-moves"] = $options["max-moves"].to_i
278+
279+ $options["least-time-per-move"] ||= 1
280+ $options["least-time-per-move"] = $options["least-time-per-move"].to_i
273281 end
274282
275283 # See if a file can be created in the directory.
--- a/shogi_server.rb
+++ b/shogi_server.rb
@@ -49,7 +49,6 @@ Max_Identifier_Length = 32
4949 Default_Timeout = 60 # for single socket operation
5050 Default_Game_Name = "default-1500-0"
5151 One_Time = 10
52-Least_Time_Per_Move = 1
5352 Login_Time = 300 # time for LOGIN
5453 Revision = "20131215"
5554
--- a/shogi_server/game.rb
+++ b/shogi_server/game.rb
@@ -71,7 +71,7 @@ class Game
7171 @total_time = $1.to_i
7272 @byoyomi = $2.to_i
7373
74- @time_clock = TimeClock::factory(Least_Time_Per_Move, @game_name)
74+ @time_clock = TimeClock::factory($options["least-time-per-move"], @game_name)
7575 end
7676
7777 if (player0.sente)
@@ -369,7 +369,7 @@ BEGIN Time
369369 Time_Unit:#{@time_clock.time_unit}
370370 Total_Time:#{@total_time}
371371 Byoyomi:#{@byoyomi}
372-Least_Time_Per_Move:#{Least_Time_Per_Move}
372+Least_Time_Per_Move:#{$options["least-time-per-move"]}
373373 Remaining_Time+:#{@sente.mytime}
374374 Remaining_Time-:#{@gote.mytime}
375375 Last_Move:#{@last_move}
@@ -403,7 +403,7 @@ BEGIN Time
403403 Time_Unit:#{@time_clock.time_unit}
404404 Total_Time:#{@total_time}
405405 Byoyomi:#{@byoyomi}
406-Least_Time_Per_Move:#{Least_Time_Per_Move}
406+Least_Time_Per_Move:#{$options["least-time-per-move"]}
407407 END Time
408408 BEGIN Position
409409 #{@board.initial_string.chomp}
--- a/shogi_server/time_clock.rb
+++ b/shogi_server/time_clock.rb
@@ -36,7 +36,11 @@ class TimeClock
3636 if (byoyomi_str == "060")
3737 @time_clock = StopWatchClock.new(least_time_per_move, total_time, byoyomi)
3838 else
39- @time_clock = ChessClock.new(least_time_per_move, total_time, byoyomi)
39+ if least_time_per_move == 0
40+ @time_clock = ChessClockWithLeastZero.new(least_time_per_move, total_time, byoyomi)
41+ else
42+ @time_clock = ChessClock.new(least_time_per_move, total_time, byoyomi)
43+ end
4044 end
4145 end
4246
@@ -48,7 +52,7 @@ class TimeClock
4852
4953 # Returns thinking time duration
5054 #
51- def time_duration(start_time, end_time)
55+ def time_duration(mytime, start_time, end_time)
5256 # implement this
5357 return 9999999
5458 end
@@ -69,7 +73,7 @@ class TimeClock
6973 # Updates a player's remaining time and returns thinking time.
7074 #
7175 def process_time(player, start_time, end_time)
72- t = time_duration(start_time, end_time)
76+ t = time_duration(player.mytime, start_time, end_time)
7377
7478 player.mytime -= t
7579 if (player.mytime < 0)
@@ -87,12 +91,12 @@ class ChessClock < TimeClock
8791 super
8892 end
8993
90- def time_duration(start_time, end_time)
94+ def time_duration(mytime, start_time, end_time)
9195 return [(end_time - start_time).floor, @least_time_per_move].max
9296 end
9397
9498 def timeout?(player, start_time, end_time)
95- t = time_duration(start_time, end_time)
99+ t = time_duration(player.mytime, start_time, end_time)
96100
97101 if ((player.mytime - t <= -@byoyomi) &&
98102 ((@total_time > 0) || (@byoyomi > 0)))
@@ -107,6 +111,42 @@ class ChessClock < TimeClock
107111 end
108112 end
109113
114+# Calculates thinking time with chess clock, truncating decimal seconds for
115+# thinking time. This is a new rule that CSA introduced in November 2014.
116+#
117+# least_time_per_move should be 0.
118+# byoyomi should be more than 0.
119+#
120+class ChessClockWithLeastZero < ChessClock
121+ def initialize(least_time_per_move, total_time, byoyomi)
122+ if least_time_per_move != 0
123+ raise ArgumentError, "least_time_per_move #{least_time_per_move} should be 0."
124+ end
125+ super
126+ end
127+
128+ def time_duration(mytime, start_time, end_time)
129+ t = end_time - start_time
130+ if @byoyomi > 0
131+ # If the remaining thinking time covers the duration t, floor it.
132+ if mytime + @byoyomi - t > 0
133+ t = t.floor
134+ else
135+ t = t.ceil
136+ end
137+ else
138+ # Thinking time only
139+ t = t.floor
140+ end
141+
142+ return t
143+ end
144+
145+ def to_s
146+ return "ChessClockWithLeastZero: LeastTimePerMove %d; TotalTime %d; Byoyomi %d" % [@least_time_per_move, @total_time, @byoyomi]
147+ end
148+end
149+
110150 class StopWatchClock < TimeClock
111151 def initialize(least_time_per_move, total_time, byoyomi)
112152 super
@@ -116,13 +156,13 @@ class StopWatchClock < TimeClock
116156 return "1min"
117157 end
118158
119- def time_duration(start_time, end_time)
159+ def time_duration(mytime, start_time, end_time)
120160 t = [(end_time - start_time).floor, @least_time_per_move].max
121161 return (t / @byoyomi) * @byoyomi
122162 end
123163
124164 def timeout?(player, start_time, end_time)
125- t = time_duration(start_time, end_time)
165+ t = time_duration(player.mytime, start_time, end_time)
126166
127167 if (player.mytime <= t)
128168 return true
--- a/test/TC_ALL.rb
+++ b/test/TC_ALL.rb
@@ -13,6 +13,7 @@ require 'TC_floodgate_thread.rb'
1313 require 'TC_fork'
1414 require 'TC_functional'
1515 require 'TC_game'
16+require 'TC_game_least_0'
1617 require 'TC_game_result'
1718 require 'TC_handicapped_boards'
1819 # This game has more thatn 256 moves.
--- a/test/TC_fork.rb
+++ b/test/TC_fork.rb
@@ -16,8 +16,11 @@ class TestFork < BaseClient
1616 def test_wrong_game
1717 @admin = SocketPlayer.new "dummy", "admin", false
1818 @admin.connect
19+ sleep 0.1
1920 @admin.reader
21+ sleep 0.1
2022 @admin.login
23+ sleep 0.1
2124
2225 result, result2 = handshake do
2326 @admin.puts "%%FORK wronggame-900-0 buoy_WrongGame-900-0"
@@ -31,8 +34,11 @@ class TestFork < BaseClient
3134 def test_too_short_fork
3235 @admin = SocketPlayer.new "dummy", "admin", false
3336 @admin.connect
37+ sleep 0.1
3438 @admin.reader
39+ sleep 0.1
3540 @admin.login
41+ sleep 0.1
3642
3743 result, result2 = handshake do
3844 source_game = parse_game_name(@admin)
@@ -49,8 +55,12 @@ class TestFork < BaseClient
4955
5056 @admin = SocketPlayer.new "dummy", "admin", "*"
5157 @admin.connect
58+ sleep 0.1
5259 @admin.reader
60+ sleep 0.1
5361 @admin.login
62+ sleep 0.1
63+
5464 assert buoy.is_new_game?("buoy_Fork-1500-0")
5565
5666 result, result2 = handshake do
@@ -63,26 +73,34 @@ class TestFork < BaseClient
6373 @p1 = SocketPlayer.new "buoy_Fork", "p1", true
6474 @p2 = SocketPlayer.new "buoy_Fork", "p2", false
6575 @p1.connect
76+ sleep 0.1
6677 @p2.connect
78+ sleep 0.1
6779 @p1.reader
80+ sleep 0.1
6881 @p2.reader
82+ sleep 0.1
6983 @p1.login
84+ sleep 0.1
7085 @p2.login
71- sleep 1
86+ sleep 0.1
7287 @p1.game
88+ sleep 0.1
7389 @p2.game
74- sleep 1
7590 @p1.agree
91+ sleep 0.1
7692 @p2.agree
77- sleep 1
93+ sleep 0.1
7894 assert /^Total_Time:1500/ =~ @p1.message
7995 assert /^Total_Time:1500/ =~ @p2.message
8096 @p2.move("-3334FU")
81- sleep 1
97+ sleep 0.1
8298 @p1.toryo
83- sleep 1
99+ sleep 0.1
84100 @p2.logout
101+ sleep 0.1
85102 @p1.logout
103+ sleep 0.1
86104
87105 @admin.logout
88106 end
@@ -92,8 +110,11 @@ class TestFork < BaseClient
92110
93111 @admin = SocketPlayer.new "dummy", "admin", "*"
94112 @admin.connect
113+ sleep 0.1
95114 @admin.reader
115+ sleep 0.1
96116 @admin.login
117+ sleep 0.1
97118
98119 result, result2 = handshake do
99120 source_game = parse_game_name(@admin)
@@ -106,26 +127,35 @@ class TestFork < BaseClient
106127 @p1 = SocketPlayer.new "buoy_TestFork_1", "p1", true
107128 @p2 = SocketPlayer.new "buoy_TestFork_1", "p2", false
108129 @p1.connect
130+ sleep 0.1
109131 @p2.connect
132+ sleep 0.1
110133 @p1.reader
134+ sleep 0.1
111135 @p2.reader
136+ sleep 0.1
112137 @p1.login
138+ sleep 0.1
113139 @p2.login
114- sleep 1
140+ sleep 0.1
115141 @p1.game
142+ sleep 0.1
116143 @p2.game
117- sleep 1
144+ sleep 0.1
118145 @p1.agree
146+ sleep 0.1
119147 @p2.agree
120- sleep 1
148+ sleep 0.1
121149 assert /^Total_Time:1500/ =~ @p1.message
122150 assert /^Total_Time:1500/ =~ @p2.message
123151 @p2.move("-3334FU")
124- sleep 1
152+ sleep 0.1
125153 @p1.toryo
126- sleep 1
154+ sleep 0.1
127155 @p2.logout
156+ sleep 0.1
128157 @p1.logout
158+ sleep 0.1
129159
130160 @admin.logout
131161 end
--- a/test/TC_game.rb
+++ b/test/TC_game.rb
@@ -5,6 +5,9 @@ require 'shogi_server/board'
55 require 'shogi_server/game'
66 require 'shogi_server/player'
77
8+$options = {}
9+$options["least-time-per-move"] = 1
10+
811 def log_message(str)
912 $stderr.puts str
1013 end
@@ -52,7 +55,7 @@ BEGIN Time
5255 Time_Unit:1sec
5356 Total_Time:1500
5457 Byoyomi:0
55-Least_Time_Per_Move:1
58+Least_Time_Per_Move:#{$options["least-time-per-move"]}
5659 END Time
5760 BEGIN Position
5861 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -86,7 +89,7 @@ BEGIN Time
8689 Time_Unit:1sec
8790 Total_Time:1500
8891 Byoyomi:0
89-Least_Time_Per_Move:1
92+Least_Time_Per_Move:#{$options["least-time-per-move"]}
9093 END Time
9194 BEGIN Position
9295 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -154,7 +157,7 @@ BEGIN Time
154157 Time_Unit:1sec
155158 Total_Time:1500
156159 Byoyomi:0
157-Least_Time_Per_Move:1
160+Least_Time_Per_Move:#{$options["least-time-per-move"]}
158161 END Time
159162 BEGIN Position
160163 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -189,7 +192,7 @@ BEGIN Time
189192 Time_Unit:1sec
190193 Total_Time:1500
191194 Byoyomi:0
192-Least_Time_Per_Move:1
195+Least_Time_Per_Move:#{$options["least-time-per-move"]}
193196 END Time
194197 BEGIN Position
195198 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -261,7 +264,7 @@ BEGIN Time
261264 Time_Unit:1sec
262265 Total_Time:1500
263266 Byoyomi:0
264-Least_Time_Per_Move:1
267+Least_Time_Per_Move:#{$options["least-time-per-move"]}
265268 END Time
266269 BEGIN Position
267270 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -297,7 +300,7 @@ BEGIN Time
297300 Time_Unit:1sec
298301 Total_Time:1500
299302 Byoyomi:0
300-Least_Time_Per_Move:1
303+Least_Time_Per_Move:#{$options["least-time-per-move"]}
301304 END Time
302305 BEGIN Position
303306 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
--- /dev/null
+++ b/test/TC_game_least_0.rb
@@ -0,0 +1,411 @@
1+$:.unshift File.join(File.dirname(__FILE__), "..")
2+require 'test/unit'
3+require 'test/mock_player'
4+require 'shogi_server/board'
5+require 'shogi_server/game'
6+require 'shogi_server/player'
7+
8+$options = {}
9+$options["least-time-per-move"] = 0
10+
11+def log_message(str)
12+ $stderr.puts str
13+end
14+
15+def log_warning(str)
16+ $stderr.puts str
17+end
18+
19+def log_error(str)
20+ $stderr.puts str
21+end
22+
23+$league = ShogiServer::League.new(File.dirname(__FILE__))
24+$league.event = "test"
25+
26+class TestGameWithLeastZero < Test::Unit::TestCase
27+
28+ def test_new
29+ game_name = "hoge-1500-10"
30+ board = ShogiServer::Board.new
31+ board.initial
32+ p1 = MockPlayer.new
33+ p1.sente = true
34+ p1.name = "p1"
35+ p2 = MockPlayer.new
36+ p2.sente = false
37+ p2.name = "p2"
38+
39+ game = ShogiServer::Game.new game_name, p1, p2, board
40+ assert_equal "", game.last_move
41+
42+ p1_out = <<EOF
43+BEGIN Game_Summary
44+Protocol_Version:1.1
45+Protocol_Mode:Server
46+Format:Shogi 1.0
47+Declaration:Jishogi 1.1
48+Game_ID:#{game.game_id}
49+Name+:p1
50+Name-:p2
51+Your_Turn:+
52+Rematch_On_Draw:NO
53+To_Move:+
54+BEGIN Time
55+Time_Unit:1sec
56+Total_Time:1500
57+Byoyomi:10
58+Least_Time_Per_Move:#{$options["least-time-per-move"]}
59+END Time
60+BEGIN Position
61+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
62+P2 * -HI * * * * * -KA *
63+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
64+P4 * * * * * * * * *
65+P5 * * * * * * * * *
66+P6 * * * * * * * * *
67+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
68+P8 * +KA * * * * * +HI *
69+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
70++
71+END Position
72+END Game_Summary
73+EOF
74+ assert_equal(p1_out, p1.out.first)
75+
76+ p2_out = <<EOF
77+BEGIN Game_Summary
78+Protocol_Version:1.1
79+Protocol_Mode:Server
80+Format:Shogi 1.0
81+Declaration:Jishogi 1.1
82+Game_ID:#{game.game_id}
83+Name+:p1
84+Name-:p2
85+Your_Turn:-
86+Rematch_On_Draw:NO
87+To_Move:+
88+BEGIN Time
89+Time_Unit:1sec
90+Total_Time:1500
91+Byoyomi:10
92+Least_Time_Per_Move:#{$options["least-time-per-move"]}
93+END Time
94+BEGIN Position
95+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
96+P2 * -HI * * * * * -KA *
97+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
98+P4 * * * * * * * * *
99+P5 * * * * * * * * *
100+P6 * * * * * * * * *
101+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
102+P8 * +KA * * * * * +HI *
103+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
104++
105+END Position
106+END Game_Summary
107+EOF
108+ assert_equal(p2_out, p2.out.first)
109+
110+ file = Pathname.new(game.logfile)
111+ log = file.read
112+ assert_equal(<<EOF, log.gsub(/^\$START_TIME.*?\n/,''))
113+V2
114+N+p1
115+N-p2
116+$EVENT:#{game.game_id}
117+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
118+P2 * -HI * * * * * -KA *
119+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
120+P4 * * * * * * * * *
121+P5 * * * * * * * * *
122+P6 * * * * * * * * *
123+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
124+P8 * +KA * * * * * +HI *
125+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
126++
127+EOF
128+ end
129+
130+ def test_new_buoy_1_move
131+ game_name = "buoyhoge-1500-10"
132+ board = ShogiServer::Board.new
133+ board.set_from_moves ["+7776FU"]
134+ p1 = MockPlayer.new
135+ p1.sente = true
136+ p1.name = "p1"
137+ p2 = MockPlayer.new
138+ p2.sente = false
139+ p2.name = "p2"
140+
141+ game = ShogiServer::Game.new game_name, p1, p2, board
142+ assert_equal "+7776FU,T1", game.last_move
143+
144+ p1_out = <<EOF
145+BEGIN Game_Summary
146+Protocol_Version:1.1
147+Protocol_Mode:Server
148+Format:Shogi 1.0
149+Declaration:Jishogi 1.1
150+Game_ID:#{game.game_id}
151+Name+:p1
152+Name-:p2
153+Your_Turn:+
154+Rematch_On_Draw:NO
155+To_Move:-
156+BEGIN Time
157+Time_Unit:1sec
158+Total_Time:1500
159+Byoyomi:10
160+Least_Time_Per_Move:#{$options["least-time-per-move"]}
161+END Time
162+BEGIN Position
163+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
164+P2 * -HI * * * * * -KA *
165+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
166+P4 * * * * * * * * *
167+P5 * * * * * * * * *
168+P6 * * * * * * * * *
169+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
170+P8 * +KA * * * * * +HI *
171+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
172++
173++7776FU,T1
174+END Position
175+END Game_Summary
176+EOF
177+ assert_equal(p1_out, p1.out.first)
178+
179+ p2_out = <<EOF
180+BEGIN Game_Summary
181+Protocol_Version:1.1
182+Protocol_Mode:Server
183+Format:Shogi 1.0
184+Declaration:Jishogi 1.1
185+Game_ID:#{game.game_id}
186+Name+:p1
187+Name-:p2
188+Your_Turn:-
189+Rematch_On_Draw:NO
190+To_Move:-
191+BEGIN Time
192+Time_Unit:1sec
193+Total_Time:1500
194+Byoyomi:10
195+Least_Time_Per_Move:#{$options["least-time-per-move"]}
196+END Time
197+BEGIN Position
198+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
199+P2 * -HI * * * * * -KA *
200+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
201+P4 * * * * * * * * *
202+P5 * * * * * * * * *
203+P6 * * * * * * * * *
204+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
205+P8 * +KA * * * * * +HI *
206+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
207++
208++7776FU,T1
209+END Position
210+END Game_Summary
211+EOF
212+ assert_equal(p2_out, p2.out.first)
213+
214+ file = Pathname.new(game.logfile)
215+ log = file.read
216+ assert_equal(<<EOF, log.gsub(/^\$START_TIME.*?\n/,''))
217+V2
218+N+p1
219+N-p2
220+$EVENT:#{game.game_id}
221+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
222+P2 * -HI * * * * * -KA *
223+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
224+P4 * * * * * * * * *
225+P5 * * * * * * * * *
226+P6 * * * * * * * * *
227+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
228+P8 * +KA * * * * * +HI *
229+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
230++
231+'buoy game starting with 1 moves
232++7776FU
233+T1
234+EOF
235+ end
236+
237+ def test_new_buoy_2_moves
238+ game_name = "buoyhoge-1500-10"
239+ board = ShogiServer::Board.new
240+ board.set_from_moves ["+7776FU", "-3334FU"]
241+ p1 = MockPlayer.new
242+ p1.sente = true
243+ p1.name = "p1"
244+ p2 = MockPlayer.new
245+ p2.sente = false
246+ p2.name = "p2"
247+
248+ game = ShogiServer::Game.new game_name, p1, p2, board
249+ assert_equal "-3334FU,T1", game.last_move
250+
251+ p1_out = <<EOF
252+BEGIN Game_Summary
253+Protocol_Version:1.1
254+Protocol_Mode:Server
255+Format:Shogi 1.0
256+Declaration:Jishogi 1.1
257+Game_ID:#{game.game_id}
258+Name+:p1
259+Name-:p2
260+Your_Turn:+
261+Rematch_On_Draw:NO
262+To_Move:+
263+BEGIN Time
264+Time_Unit:1sec
265+Total_Time:1500
266+Byoyomi:10
267+Least_Time_Per_Move:#{$options["least-time-per-move"]}
268+END Time
269+BEGIN Position
270+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
271+P2 * -HI * * * * * -KA *
272+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
273+P4 * * * * * * * * *
274+P5 * * * * * * * * *
275+P6 * * * * * * * * *
276+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
277+P8 * +KA * * * * * +HI *
278+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
279++
280++7776FU,T1
281+-3334FU,T1
282+END Position
283+END Game_Summary
284+EOF
285+ assert_equal(p1_out, p1.out.first)
286+
287+ p2_out = <<EOF
288+BEGIN Game_Summary
289+Protocol_Version:1.1
290+Protocol_Mode:Server
291+Format:Shogi 1.0
292+Declaration:Jishogi 1.1
293+Game_ID:#{game.game_id}
294+Name+:p1
295+Name-:p2
296+Your_Turn:-
297+Rematch_On_Draw:NO
298+To_Move:+
299+BEGIN Time
300+Time_Unit:1sec
301+Total_Time:1500
302+Byoyomi:10
303+Least_Time_Per_Move:#{$options["least-time-per-move"]}
304+END Time
305+BEGIN Position
306+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
307+P2 * -HI * * * * * -KA *
308+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
309+P4 * * * * * * * * *
310+P5 * * * * * * * * *
311+P6 * * * * * * * * *
312+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
313+P8 * +KA * * * * * +HI *
314+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
315++
316++7776FU,T1
317+-3334FU,T1
318+END Position
319+END Game_Summary
320+EOF
321+ assert_equal(p2_out, p2.out.first)
322+
323+ file = Pathname.new(game.logfile)
324+ log = file.read
325+ assert_equal(<<EOF, log.gsub(/^\$START_TIME.*?\n/,''))
326+V2
327+N+p1
328+N-p2
329+$EVENT:#{game.game_id}
330+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
331+P2 * -HI * * * * * -KA *
332+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
333+P4 * * * * * * * * *
334+P5 * * * * * * * * *
335+P6 * * * * * * * * *
336+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
337+P8 * +KA * * * * * +HI *
338+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
339++
340+'buoy game starting with 2 moves
341++7776FU
342+T1
343+-3334FU
344+T1
345+EOF
346+ end
347+
348+ def test_monitor_add
349+ game_name = "hoge-1500-10"
350+ board = ShogiServer::Board.new
351+ board.initial
352+ p1 = MockPlayer.new
353+ p1.sente = true
354+ p1.name = "p1"
355+ p2 = MockPlayer.new
356+ p2.sente = false
357+ p2.name = "p2"
358+
359+ game = ShogiServer::Game.new game_name, p1, p2, board
360+ handler1 = ShogiServer::MonitorHandler1.new p1
361+ handler2 = ShogiServer::MonitorHandler2.new p2
362+
363+ assert_equal(0, game.monitors.size)
364+ game.monitoron(handler1)
365+ assert_equal(1, game.monitors.size)
366+ game.monitoron(handler2)
367+ assert_equal(2, game.monitors.size)
368+ game.monitoroff(handler1)
369+ assert_equal(1, game.monitors.size)
370+ assert_equal(handler2, game.monitors.last)
371+ game.monitoroff(handler2)
372+ assert_equal(0, game.monitors.size)
373+ end
374+
375+ def test_decide_turns
376+ p1 = MockPlayer.new
377+ p1.name = "p1"
378+ p2 = MockPlayer.new
379+ p2.name = "p2"
380+
381+ p1.sente=nil; p2.sente=false
382+ ShogiServer::Game::decide_turns(p1, "+", p2)
383+ assert_equal true, p1.sente
384+
385+ p1.sente=nil; p2.sente=nil
386+ ShogiServer::Game::decide_turns(p1, "+", p2)
387+ assert_equal true, p1.sente
388+
389+ p1.sente=nil; p2.sente=true
390+ ShogiServer::Game::decide_turns(p1, "-", p2)
391+ assert_equal false, p1.sente
392+
393+ p1.sente=nil; p2.sente=nil
394+ ShogiServer::Game::decide_turns(p1, "-", p2)
395+ assert_equal false, p1.sente
396+
397+ p1.sente=nil; p2.sente=false
398+ ShogiServer::Game::decide_turns(p1, "*", p2)
399+ assert_equal true, p1.sente
400+
401+ p1.sente=nil; p2.sente=true
402+ ShogiServer::Game::decide_turns(p1, "*", p2)
403+ assert_equal false, p1.sente
404+
405+ p1.sente=nil; p2.sente=nil
406+ ShogiServer::Game::decide_turns(p1, "*", p2)
407+ assert (p1.sente == true && p2.sente == false) ||
408+ (p1.sente == false && p2.sente == true)
409+ end
410+end
411+
--- a/test/TC_time_clock.rb
+++ b/test/TC_time_clock.rb
@@ -30,11 +30,11 @@ end
3030 class TestChessClock < Test::Unit::TestCase
3131 def test_time_duration
3232 tc = ShogiServer::ChessClock.new(1, 1500, 60)
33- assert_equal(1, tc.time_duration(100.1, 100.9))
34- assert_equal(1, tc.time_duration(100, 101))
35- assert_equal(1, tc.time_duration(100.1, 101.9))
36- assert_equal(2, tc.time_duration(100.1, 102.9))
37- assert_equal(2, tc.time_duration(100, 102))
33+ assert_equal(1, tc.time_duration(nil, 100.1, 100.9))
34+ assert_equal(1, tc.time_duration(nil, 100, 101))
35+ assert_equal(1, tc.time_duration(nil, 100.1, 101.9))
36+ assert_equal(2, tc.time_duration(nil, 100.1, 102.9))
37+ assert_equal(2, tc.time_duration(nil, 100, 102))
3838 end
3939
4040 def test_without_byoyomi
@@ -70,15 +70,56 @@ class TestChessClock < Test::Unit::TestCase
7070 end
7171 end
7272
73+class TestChessClockWithLeastZero < Test::Unit::TestCase
74+ def test_time_duration_within_thinking_time
75+ tc = ShogiServer::ChessClockWithLeastZero.new(0, 900, 10)
76+ assert_equal(0, tc.time_duration(100, 100.1, 100.9)) # 0.8
77+ assert_equal(1, tc.time_duration(100, 100, 101)) # 1
78+ assert_equal(1, tc.time_duration(100, 100.1, 101.9)) # 1.8
79+ assert_equal(1, tc.time_duration(1, 100, 101)) # 1
80+ assert_equal(2, tc.time_duration(100, 100.1, 102.9)) # 2.8
81+ assert_equal(2, tc.time_duration(100, 100, 102)) # 2
82+ end
83+
84+ def test_time_duration_over_thinking_time
85+ tc = ShogiServer::ChessClockWithLeastZero.new(0, 900, 10)
86+ assert_equal(1, tc.time_duration(1, 100.1, 101.9)) # 1.8
87+ assert_equal(2, tc.time_duration(2, 100.1, 102.9)) # 2.8
88+ end
89+
90+ def test_with_byoyomi
91+ tc = ShogiServer::ChessClockWithLeastZero.new(0, 900, 10)
92+
93+ p = DummyPlayer.new 100
94+ assert(!tc.timeout?(p, 100, 101)) # 1
95+ assert(!tc.timeout?(p, 100, 209)) # 109
96+ assert(!tc.timeout?(p, 100, 209.9)) # 109.9
97+ assert(tc.timeout?(p, 100, 210)) # 110
98+ assert(tc.timeout?(p, 100, 210.1)) # 110.1
99+ assert(tc.timeout?(p, 100, 211)) # 111
100+ end
101+
102+ def test_with_byoyomi2
103+ tc = ShogiServer::ChessClockWithLeastZero.new(0, 0, 10)
104+
105+ p = DummyPlayer.new 0
106+ assert(!tc.timeout?(p, 100, 109)) # 9
107+ assert(!tc.timeout?(p, 100, 109.9)) # 9.9
108+ assert(tc.timeout?(p, 100, 110)) # 10
109+ assert(tc.timeout?(p, 100, 110.1)) # 10.1
110+ assert(tc.timeout?(p, 100, 110)) # 10.1
111+ end
112+end
113+
73114 class TestStopWatchClock < Test::Unit::TestCase
74115 def test_time_duration
75116 tc = ShogiServer::StopWatchClock.new(1, 1500, 60)
76- assert_equal(0, tc.time_duration(100.1, 100.9))
77- assert_equal(0, tc.time_duration(100, 101))
78- assert_equal(0, tc.time_duration(100, 159.9))
79- assert_equal(60, tc.time_duration(100, 160))
80- assert_equal(60, tc.time_duration(100, 219))
81- assert_equal(120, tc.time_duration(100, 220))
117+ assert_equal(0, tc.time_duration(nil, 100.1, 100.9))
118+ assert_equal(0, tc.time_duration(nil, 100, 101))
119+ assert_equal(0, tc.time_duration(nil, 100, 159.9))
120+ assert_equal(60, tc.time_duration(nil, 100, 160))
121+ assert_equal(60, tc.time_duration(nil, 100, 219))
122+ assert_equal(120, tc.time_duration(nil, 100, 220))
82123 end
83124
84125 def test_with_byoyomi
--- a/test/baseclient.rb
+++ b/test/baseclient.rb
@@ -178,20 +178,32 @@ class BaseClient < Test::Unit::TestCase
178178 end
179179
180180 def login
181+ sleep 0.1
181182 @p1.connect
183+ sleep 0.1
182184 @p2.connect
185+ sleep 0.1
183186 @p1.login
187+ sleep 0.1
184188 @p2.login
189+ sleep 0.1
185190 @p1.game
191+ sleep 0.1
186192 @p2.game
193+ sleep 0.1
187194 @p1.wait_game
195+ sleep 0.1
188196 @p2.wait_game
189197 end
190198
191199 def agree
200+ sleep 0.1
192201 @p1.agree
202+ sleep 0.1
193203 @p2.agree
204+ sleep 0.1
194205 @p1.wait_agree
206+ sleep 0.1
195207 @p2.wait_agree
196208 end
197209