shogi-server source
Révision | b0a2884dfa2bde82572e2156a7b6ec142bed51f5 (tree) |
---|---|
l'heure | 2015-01-12 21:54:42 |
Auteur | Daigo Moriwaki <daigo@debi...> |
Commiter | Daigo Moriwaki |
New feature: Zero least time per move.
New command line option: --least-time-per-move n
@@ -12,6 +12,11 @@ | ||
12 | 12 | - A new log summary type, "max_moves_draw", has been assigned for games |
13 | 13 | drawing with max moves. |
14 | 14 | '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. | |
15 | 20 | |
16 | 21 | 2014-07-19 Daigo Moriwaki <daigo at debian dot org> |
17 | 22 |
@@ -76,6 +76,10 @@ OPTIONS | ||
76 | 76 | port_number |
77 | 77 | a port number for the server to listen. |
78 | 78 | 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. | |
79 | 83 | --max-moves n |
80 | 84 | when a game with the n-th move played does not end, make the game a draw. |
81 | 85 | Default 256. 0 disables this feature. |
@@ -194,11 +198,12 @@ end | ||
194 | 198 | def parse_command_line |
195 | 199 | options = Hash::new |
196 | 200 | 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]) | |
202 | 207 | parser.quiet = true |
203 | 208 | begin |
204 | 209 | parser.each_option do |name, arg| |
@@ -270,6 +275,9 @@ def check_command_line | ||
270 | 275 | |
271 | 276 | $options["max-moves"] ||= 256 |
272 | 277 | $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 | |
273 | 281 | end |
274 | 282 | |
275 | 283 | # See if a file can be created in the directory. |
@@ -49,7 +49,6 @@ Max_Identifier_Length = 32 | ||
49 | 49 | Default_Timeout = 60 # for single socket operation |
50 | 50 | Default_Game_Name = "default-1500-0" |
51 | 51 | One_Time = 10 |
52 | -Least_Time_Per_Move = 1 | |
53 | 52 | Login_Time = 300 # time for LOGIN |
54 | 53 | Revision = "20131215" |
55 | 54 |
@@ -71,7 +71,7 @@ class Game | ||
71 | 71 | @total_time = $1.to_i |
72 | 72 | @byoyomi = $2.to_i |
73 | 73 | |
74 | - @time_clock = TimeClock::factory(Least_Time_Per_Move, @game_name) | |
74 | + @time_clock = TimeClock::factory($options["least-time-per-move"], @game_name) | |
75 | 75 | end |
76 | 76 | |
77 | 77 | if (player0.sente) |
@@ -369,7 +369,7 @@ BEGIN Time | ||
369 | 369 | Time_Unit:#{@time_clock.time_unit} |
370 | 370 | Total_Time:#{@total_time} |
371 | 371 | Byoyomi:#{@byoyomi} |
372 | -Least_Time_Per_Move:#{Least_Time_Per_Move} | |
372 | +Least_Time_Per_Move:#{$options["least-time-per-move"]} | |
373 | 373 | Remaining_Time+:#{@sente.mytime} |
374 | 374 | Remaining_Time-:#{@gote.mytime} |
375 | 375 | Last_Move:#{@last_move} |
@@ -403,7 +403,7 @@ BEGIN Time | ||
403 | 403 | Time_Unit:#{@time_clock.time_unit} |
404 | 404 | Total_Time:#{@total_time} |
405 | 405 | Byoyomi:#{@byoyomi} |
406 | -Least_Time_Per_Move:#{Least_Time_Per_Move} | |
406 | +Least_Time_Per_Move:#{$options["least-time-per-move"]} | |
407 | 407 | END Time |
408 | 408 | BEGIN Position |
409 | 409 | #{@board.initial_string.chomp} |
@@ -36,7 +36,11 @@ class TimeClock | ||
36 | 36 | if (byoyomi_str == "060") |
37 | 37 | @time_clock = StopWatchClock.new(least_time_per_move, total_time, byoyomi) |
38 | 38 | 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 | |
40 | 44 | end |
41 | 45 | end |
42 | 46 |
@@ -48,7 +52,7 @@ class TimeClock | ||
48 | 52 | |
49 | 53 | # Returns thinking time duration |
50 | 54 | # |
51 | - def time_duration(start_time, end_time) | |
55 | + def time_duration(mytime, start_time, end_time) | |
52 | 56 | # implement this |
53 | 57 | return 9999999 |
54 | 58 | end |
@@ -69,7 +73,7 @@ class TimeClock | ||
69 | 73 | # Updates a player's remaining time and returns thinking time. |
70 | 74 | # |
71 | 75 | 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) | |
73 | 77 | |
74 | 78 | player.mytime -= t |
75 | 79 | if (player.mytime < 0) |
@@ -87,12 +91,12 @@ class ChessClock < TimeClock | ||
87 | 91 | super |
88 | 92 | end |
89 | 93 | |
90 | - def time_duration(start_time, end_time) | |
94 | + def time_duration(mytime, start_time, end_time) | |
91 | 95 | return [(end_time - start_time).floor, @least_time_per_move].max |
92 | 96 | end |
93 | 97 | |
94 | 98 | 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) | |
96 | 100 | |
97 | 101 | if ((player.mytime - t <= -@byoyomi) && |
98 | 102 | ((@total_time > 0) || (@byoyomi > 0))) |
@@ -107,6 +111,42 @@ class ChessClock < TimeClock | ||
107 | 111 | end |
108 | 112 | end |
109 | 113 | |
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 | + | |
110 | 150 | class StopWatchClock < TimeClock |
111 | 151 | def initialize(least_time_per_move, total_time, byoyomi) |
112 | 152 | super |
@@ -116,13 +156,13 @@ class StopWatchClock < TimeClock | ||
116 | 156 | return "1min" |
117 | 157 | end |
118 | 158 | |
119 | - def time_duration(start_time, end_time) | |
159 | + def time_duration(mytime, start_time, end_time) | |
120 | 160 | t = [(end_time - start_time).floor, @least_time_per_move].max |
121 | 161 | return (t / @byoyomi) * @byoyomi |
122 | 162 | end |
123 | 163 | |
124 | 164 | 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) | |
126 | 166 | |
127 | 167 | if (player.mytime <= t) |
128 | 168 | return true |
@@ -13,6 +13,7 @@ require 'TC_floodgate_thread.rb' | ||
13 | 13 | require 'TC_fork' |
14 | 14 | require 'TC_functional' |
15 | 15 | require 'TC_game' |
16 | +require 'TC_game_least_0' | |
16 | 17 | require 'TC_game_result' |
17 | 18 | require 'TC_handicapped_boards' |
18 | 19 | # This game has more thatn 256 moves. |
@@ -16,8 +16,11 @@ class TestFork < BaseClient | ||
16 | 16 | def test_wrong_game |
17 | 17 | @admin = SocketPlayer.new "dummy", "admin", false |
18 | 18 | @admin.connect |
19 | + sleep 0.1 | |
19 | 20 | @admin.reader |
21 | + sleep 0.1 | |
20 | 22 | @admin.login |
23 | + sleep 0.1 | |
21 | 24 | |
22 | 25 | result, result2 = handshake do |
23 | 26 | @admin.puts "%%FORK wronggame-900-0 buoy_WrongGame-900-0" |
@@ -31,8 +34,11 @@ class TestFork < BaseClient | ||
31 | 34 | def test_too_short_fork |
32 | 35 | @admin = SocketPlayer.new "dummy", "admin", false |
33 | 36 | @admin.connect |
37 | + sleep 0.1 | |
34 | 38 | @admin.reader |
39 | + sleep 0.1 | |
35 | 40 | @admin.login |
41 | + sleep 0.1 | |
36 | 42 | |
37 | 43 | result, result2 = handshake do |
38 | 44 | source_game = parse_game_name(@admin) |
@@ -49,8 +55,12 @@ class TestFork < BaseClient | ||
49 | 55 | |
50 | 56 | @admin = SocketPlayer.new "dummy", "admin", "*" |
51 | 57 | @admin.connect |
58 | + sleep 0.1 | |
52 | 59 | @admin.reader |
60 | + sleep 0.1 | |
53 | 61 | @admin.login |
62 | + sleep 0.1 | |
63 | + | |
54 | 64 | assert buoy.is_new_game?("buoy_Fork-1500-0") |
55 | 65 | |
56 | 66 | result, result2 = handshake do |
@@ -63,26 +73,34 @@ class TestFork < BaseClient | ||
63 | 73 | @p1 = SocketPlayer.new "buoy_Fork", "p1", true |
64 | 74 | @p2 = SocketPlayer.new "buoy_Fork", "p2", false |
65 | 75 | @p1.connect |
76 | + sleep 0.1 | |
66 | 77 | @p2.connect |
78 | + sleep 0.1 | |
67 | 79 | @p1.reader |
80 | + sleep 0.1 | |
68 | 81 | @p2.reader |
82 | + sleep 0.1 | |
69 | 83 | @p1.login |
84 | + sleep 0.1 | |
70 | 85 | @p2.login |
71 | - sleep 1 | |
86 | + sleep 0.1 | |
72 | 87 | @p1.game |
88 | + sleep 0.1 | |
73 | 89 | @p2.game |
74 | - sleep 1 | |
75 | 90 | @p1.agree |
91 | + sleep 0.1 | |
76 | 92 | @p2.agree |
77 | - sleep 1 | |
93 | + sleep 0.1 | |
78 | 94 | assert /^Total_Time:1500/ =~ @p1.message |
79 | 95 | assert /^Total_Time:1500/ =~ @p2.message |
80 | 96 | @p2.move("-3334FU") |
81 | - sleep 1 | |
97 | + sleep 0.1 | |
82 | 98 | @p1.toryo |
83 | - sleep 1 | |
99 | + sleep 0.1 | |
84 | 100 | @p2.logout |
101 | + sleep 0.1 | |
85 | 102 | @p1.logout |
103 | + sleep 0.1 | |
86 | 104 | |
87 | 105 | @admin.logout |
88 | 106 | end |
@@ -92,8 +110,11 @@ class TestFork < BaseClient | ||
92 | 110 | |
93 | 111 | @admin = SocketPlayer.new "dummy", "admin", "*" |
94 | 112 | @admin.connect |
113 | + sleep 0.1 | |
95 | 114 | @admin.reader |
115 | + sleep 0.1 | |
96 | 116 | @admin.login |
117 | + sleep 0.1 | |
97 | 118 | |
98 | 119 | result, result2 = handshake do |
99 | 120 | source_game = parse_game_name(@admin) |
@@ -106,26 +127,35 @@ class TestFork < BaseClient | ||
106 | 127 | @p1 = SocketPlayer.new "buoy_TestFork_1", "p1", true |
107 | 128 | @p2 = SocketPlayer.new "buoy_TestFork_1", "p2", false |
108 | 129 | @p1.connect |
130 | + sleep 0.1 | |
109 | 131 | @p2.connect |
132 | + sleep 0.1 | |
110 | 133 | @p1.reader |
134 | + sleep 0.1 | |
111 | 135 | @p2.reader |
136 | + sleep 0.1 | |
112 | 137 | @p1.login |
138 | + sleep 0.1 | |
113 | 139 | @p2.login |
114 | - sleep 1 | |
140 | + sleep 0.1 | |
115 | 141 | @p1.game |
142 | + sleep 0.1 | |
116 | 143 | @p2.game |
117 | - sleep 1 | |
144 | + sleep 0.1 | |
118 | 145 | @p1.agree |
146 | + sleep 0.1 | |
119 | 147 | @p2.agree |
120 | - sleep 1 | |
148 | + sleep 0.1 | |
121 | 149 | assert /^Total_Time:1500/ =~ @p1.message |
122 | 150 | assert /^Total_Time:1500/ =~ @p2.message |
123 | 151 | @p2.move("-3334FU") |
124 | - sleep 1 | |
152 | + sleep 0.1 | |
125 | 153 | @p1.toryo |
126 | - sleep 1 | |
154 | + sleep 0.1 | |
127 | 155 | @p2.logout |
156 | + sleep 0.1 | |
128 | 157 | @p1.logout |
158 | + sleep 0.1 | |
129 | 159 | |
130 | 160 | @admin.logout |
131 | 161 | end |
@@ -5,6 +5,9 @@ require 'shogi_server/board' | ||
5 | 5 | require 'shogi_server/game' |
6 | 6 | require 'shogi_server/player' |
7 | 7 | |
8 | +$options = {} | |
9 | +$options["least-time-per-move"] = 1 | |
10 | + | |
8 | 11 | def log_message(str) |
9 | 12 | $stderr.puts str |
10 | 13 | end |
@@ -52,7 +55,7 @@ BEGIN Time | ||
52 | 55 | Time_Unit:1sec |
53 | 56 | Total_Time:1500 |
54 | 57 | Byoyomi:0 |
55 | -Least_Time_Per_Move:1 | |
58 | +Least_Time_Per_Move:#{$options["least-time-per-move"]} | |
56 | 59 | END Time |
57 | 60 | BEGIN Position |
58 | 61 | P1-KY-KE-GI-KI-OU-KI-GI-KE-KY |
@@ -86,7 +89,7 @@ BEGIN Time | ||
86 | 89 | Time_Unit:1sec |
87 | 90 | Total_Time:1500 |
88 | 91 | Byoyomi:0 |
89 | -Least_Time_Per_Move:1 | |
92 | +Least_Time_Per_Move:#{$options["least-time-per-move"]} | |
90 | 93 | END Time |
91 | 94 | BEGIN Position |
92 | 95 | P1-KY-KE-GI-KI-OU-KI-GI-KE-KY |
@@ -154,7 +157,7 @@ BEGIN Time | ||
154 | 157 | Time_Unit:1sec |
155 | 158 | Total_Time:1500 |
156 | 159 | Byoyomi:0 |
157 | -Least_Time_Per_Move:1 | |
160 | +Least_Time_Per_Move:#{$options["least-time-per-move"]} | |
158 | 161 | END Time |
159 | 162 | BEGIN Position |
160 | 163 | P1-KY-KE-GI-KI-OU-KI-GI-KE-KY |
@@ -189,7 +192,7 @@ BEGIN Time | ||
189 | 192 | Time_Unit:1sec |
190 | 193 | Total_Time:1500 |
191 | 194 | Byoyomi:0 |
192 | -Least_Time_Per_Move:1 | |
195 | +Least_Time_Per_Move:#{$options["least-time-per-move"]} | |
193 | 196 | END Time |
194 | 197 | BEGIN Position |
195 | 198 | P1-KY-KE-GI-KI-OU-KI-GI-KE-KY |
@@ -261,7 +264,7 @@ BEGIN Time | ||
261 | 264 | Time_Unit:1sec |
262 | 265 | Total_Time:1500 |
263 | 266 | Byoyomi:0 |
264 | -Least_Time_Per_Move:1 | |
267 | +Least_Time_Per_Move:#{$options["least-time-per-move"]} | |
265 | 268 | END Time |
266 | 269 | BEGIN Position |
267 | 270 | P1-KY-KE-GI-KI-OU-KI-GI-KE-KY |
@@ -297,7 +300,7 @@ BEGIN Time | ||
297 | 300 | Time_Unit:1sec |
298 | 301 | Total_Time:1500 |
299 | 302 | Byoyomi:0 |
300 | -Least_Time_Per_Move:1 | |
303 | +Least_Time_Per_Move:#{$options["least-time-per-move"]} | |
301 | 304 | END Time |
302 | 305 | BEGIN Position |
303 | 306 | P1-KY-KE-GI-KI-OU-KI-GI-KE-KY |
@@ -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 | + |
@@ -30,11 +30,11 @@ end | ||
30 | 30 | class TestChessClock < Test::Unit::TestCase |
31 | 31 | def test_time_duration |
32 | 32 | 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)) | |
38 | 38 | end |
39 | 39 | |
40 | 40 | def test_without_byoyomi |
@@ -70,15 +70,56 @@ class TestChessClock < Test::Unit::TestCase | ||
70 | 70 | end |
71 | 71 | end |
72 | 72 | |
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 | + | |
73 | 114 | class TestStopWatchClock < Test::Unit::TestCase |
74 | 115 | def test_time_duration |
75 | 116 | 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)) | |
82 | 123 | end |
83 | 124 | |
84 | 125 | def test_with_byoyomi |
@@ -178,20 +178,32 @@ class BaseClient < Test::Unit::TestCase | ||
178 | 178 | end |
179 | 179 | |
180 | 180 | def login |
181 | + sleep 0.1 | |
181 | 182 | @p1.connect |
183 | + sleep 0.1 | |
182 | 184 | @p2.connect |
185 | + sleep 0.1 | |
183 | 186 | @p1.login |
187 | + sleep 0.1 | |
184 | 188 | @p2.login |
189 | + sleep 0.1 | |
185 | 190 | @p1.game |
191 | + sleep 0.1 | |
186 | 192 | @p2.game |
193 | + sleep 0.1 | |
187 | 194 | @p1.wait_game |
195 | + sleep 0.1 | |
188 | 196 | @p2.wait_game |
189 | 197 | end |
190 | 198 | |
191 | 199 | def agree |
200 | + sleep 0.1 | |
192 | 201 | @p1.agree |
202 | + sleep 0.1 | |
193 | 203 | @p2.agree |
204 | + sleep 0.1 | |
194 | 205 | @p1.wait_agree |
206 | + sleep 0.1 | |
195 | 207 | @p2.wait_agree |
196 | 208 | end |
197 | 209 |