.PHONY: test-run
test-run:
- ./shogi-server --floodgate-games floodgate-900-0,floodgate-3600-0 hoge 4000
+ ./shogi-server --floodgate-games floodgate-600-10,floodgate-3600-0 hoge 4000
.PHONY: test-run-daemon
test-run-daemon:
- ./shogi-server --floodgate-games floodgate-900-0,floodgate-3600-0 --daemon . --pid-file ./shogi-server.pid --player-log-dir ./player-logs hoge 4000
+ ./shogi-server --floodgate-games floodgate-600-10,floodgate-3600-0 --daemon . --pid-file ./shogi-server.pid --player-log-dir ./player-logs hoge 4000
.PHONY: stop-daemn
stop-daemon:
+2015-12-13 Daigo Moriwaki <daigo at debian dot org>
+
+ * [shogi-server] Enhance capability of Floodgate configuration file
+ - New parameter: Max_Moves, defined in the CSA protocol
+ ex. set Max_Moves 256
+ - New parameter: Least_Time_Per_Move, defined in the CSA protocol
+ ex. set Least_Time_Per_Move 0
+ - Proposed messages distributed to each player upon starting a new
+ game will include Max_Moves as well as Least_Time_Per_Move.
+ - CSA files produced by the server will include settings of
+ Max_Moves and Least_Time_Per_Move in comment lines as follows:
+ 'Max_Moves:256
+ 'Least_Time_Per_Move:0
+ - The official Shogi-server on wdoor.c.u-tokyo.ac.jp will
+ be running with different parameters, depending on game names.
+ a) Max_Moves will be 256 for floodgate-600-10 games;
+ otherwise, 0.
+ b) Least_Time_Per_Move will be 0 for floodgate-600-10 games;
+ otherwise 1.
+ (Closes: #35839)
+
2015-11-27 Daigo Moriwaki <daigo at debian dot org>
* [shogi-server] shogi_server/time_clock.rb:
$options["floodgate-history"] = nil
end
- $options["max-moves"] ||= 256
+ $options["max-moves"] ||= ShogiServer::Default_Max_Moves
$options["max-moves"] = $options["max-moves"].to_i
- $options["least-time-per-move"] ||= 0
+ $options["least-time-per-move"] ||= ShogiServer::Default_Least_Time_Per_Move
$options["least-time-per-move"] = $options["least-time-per-move"].to_i
end
Max_Identifier_Length = 32
Default_Timeout = 60 # for single socket operation
Default_Game_Name = "default-1500-0"
+Default_Max_Moves = 256
+Default_Least_Time_Per_Move = 0
One_Time = 10
Login_Time = 300 # time for LOGIN
-Revision = "20150117"
+Revision = "20151213"
RELOAD_FILES = ["shogi_server/league/floodgate.rb",
"shogi_server/league/persistent.rb",
end
- def initialize(move_count=0)
+ def initialize(options={})
@sente_hands = Array::new
@gote_hands = Array::new
@history = Hash::new(0)
@sente_history = Hash::new(0)
@gote_history = Hash::new(0)
@array = [[], [], [], [], [], [], [], [], [], []]
- @move_count = move_count
+ @move_count = 0
@teban = nil # black => true, white => false
@initial_moves = []
@move = nil
@ous = [nil, nil] # keep OU pieces of Sente and Gote
+
+ @max_moves = options[:max_moves] ||
+ ($options && $options["max-moves"]) ||
+ Default_Max_Moves
+ @least_time_per_move = options[:least_time_per_move] ||
+ ($options && $options["least-time-per-move"]) ||
+ Default_Least_Time_Per_Move
end
attr_accessor :array, :sente_hands, :gote_hands, :history, :sente_history, :gote_history, :teban
attr_reader :move_count
#
attr_reader :move
+ # Max_Moves of the CSA protocol
+ attr_reader :max_moves
+
+ # Least_Time_Per_Move of the CSA protocol
+ attr_reader :least_time_per_move
+
# See if self equals rhs, including a logical board position (i.e.
# not see object IDs) and sennichite stuff.
#
# New rule that CSA introduced in November 2014.
# If a game with 256 plies does not end, make the game a draw.
# When running test cases $options might be nil.
- if $options && $options["max-moves"] &&
- $options["max-moves"] > 0 && @move_count >= $options["max-moves"]
+ if @max_moves > 0 && @move_count >= @max_moves
return :max_moves
end
@total_time = $1.to_i
@byoyomi = $2.to_i
- @time_clock = TimeClock::factory($options["least-time-per-move"], @game_name)
+ @time_clock = TimeClock::factory(board.least_time_per_move, @game_name)
end
if (player0.sente)
@fh.puts("V2")
@fh.puts("N+#{@sente.name}")
@fh.puts("N-#{@gote.name}")
+ @fh.puts("'Max_Moves:#{@board.max_moves}")
+ @fh.puts("'Least_Time_Per_Move:#{@board.least_time_per_move}")
@fh.puts("$EVENT:#{@game_id}")
@sente.write_safe(propose_message("+"))
Name-:#{@gote.name}
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{@board.max_moves}
BEGIN Time
Time_Unit:#{@time_clock.time_unit}
Total_Time:#{@total_time}
Byoyomi:#{@byoyomi}
-Least_Time_Per_Move:#{$options["least-time-per-move"]}
+Least_Time_Per_Move:#{@board.least_time_per_move}
Remaining_Time+:#{@sente.mytime}
Remaining_Time-:#{@gote.mytime}
Last_Move:#{@last_move}
Your_Turn:#{sg_flag}
Rematch_On_Draw:NO
To_Move:#{@board.teban ? "+" : "-"}
+Max_Moves:#{@board.max_moves}
BEGIN Time
Time_Unit:#{@time_clock.time_unit}
Total_Time:#{@total_time}
Byoyomi:#{@byoyomi}
-Least_Time_Per_Move:#{$options["least-time-per-move"]}
+Least_Time_Per_Move:#{@board.least_time_per_move}
END Time
BEGIN Position
#{@board.initial_string.chomp}
# Options will be updated by NextTimeGenerator and then passed to a
# pairing factory.
@options = {}
- @options[:pairing_factory] = hash[:pairing_factory] || "default_factory"
- @options[:sacrifice] = hash[:sacrifice] || "gps500+e293220e3f8a3e59f79f6b0efffaa931"
+ @options[:pairing_factory] = hash[:pairing_factory] || "default_factory"
+ @options[:sacrifice] = hash[:sacrifice] || "gps500+e293220e3f8a3e59f79f6b0efffaa931"
+ @options[:max_moves] = hash[:max_moves] || Default_Max_Moves
+ @options[:least_time_per_move] = hash[:least_time_per_move] || Default_Least_Time_Per_Move
charge if @next_time.nil?
end
return @options[:sacrifice]
end
+ def max_moves
+ return @options[:max_moves]
+ end
+
+ def least_time_per_move
+ return @options[:least_time_per_move]
+ end
+
def charge
ntg = NextTimeGenerator.factory(@game_name)
if ntg
@next_time = ntg.call(Time.now)
- @options[:pairing_factory] = ntg.pairing_factory
- @options[:sacrifice] = ntg.sacrifice
+ @options[:pairing_factory] = ntg.pairing_factory
+ @options[:sacrifice] = ntg.sacrifice
+ @options[:max_moves] = ntg.max_moves
+ @options[:least_time_per_move] = ntg.least_time_per_move
else
@next_time = nil
end
def match_game
log_message("Starting Floodgate games...: %s, %s" % [@game_name, @options])
logics = Pairing.send(@options[:pairing_factory], @options)
- Pairing.match(select_players(), logics)
+ Pairing.match(select_players(), logics, @options)
end
#
attr_reader :pairing_factory
attr_reader :sacrifice
+ attr_reader :max_moves
+ attr_reader :least_time_per_move
# Constructor.
#
def initialize
- @pairing_factory = "default_factory"
- @sacrifice = "gps500+e293220e3f8a3e59f79f6b0efffaa931"
+ @pairing_factory = "default_factory"
+ @sacrifice = "gps500+e293220e3f8a3e59f79f6b0efffaa931"
+ @max_moves = Default_Max_Moves
+ @least_time_per_move = Default_Least_Time_Per_Move
end
end
# * sacrifice:
# Specifies a sacrificed player.
# ex. set sacrifice gps500+e293220e3f8a3e59f79f6b0efffaa931
+ # * max_moves:
+ # Sepcifies a number of max moves
+ # ex. set max_moves 256
+ # * least_time_per_move:
+ # Sepcifies a least time per move
+ # ex. set least_time_per_move 0
#
class NextTimeGeneratorConfig < AbstructNextTimeGenerator
@pairing_factory = $1.chomp
when %r!^\s*set\s+sacrifice\s+(.*)!
@sacrifice = $1.chomp
+ when %r!^\s*set\s+max_moves\s+(\d+)!
+ @max_moves = $1.chomp.to_i
+ when %r!^\s*set\s+least_time_per_move\s+(\d+)!
+ @least_time_per_move = $1.chomp.to_i
when %r!^\s*(\w+)\s+(\d{1,2}):(\d{1,2})!
dow, hour, minute = $1, $2.to_i, $3.to_i
dow_index = ::ShogiServer::parse_dow(dow)
#
def regenerate_leagues(next_instances)
leagues = next_instances.collect do |prev|
- log_message("Regenerating a floodgate league...: %s %s %s %s" %
- [prev.game_name, prev.next_time, prev.pairing_factory, prev.sacrifice])
+ log_message("Regenerating a floodgate league...: %s %s %s %s %d %d" %
+ [prev.game_name, prev.next_time, prev.pairing_factory, prev.sacrifice, prev.max_moves, prev.least_time_per_move])
floodgate = ShogiServer::League::Floodgate.new($league,
{:game_name => prev.game_name, :next_time => prev.next_time,
- :pairing_factory => prev.pairing_factory, :sacrifice => prev.sacrifice})
+ :pairing_factory => prev.pairing_factory, :sacrifice => prev.sacrifice,
+ :max_moves => prev.max_moves, :least_time_per_move => prev.least_time_per_move})
end
floodgate_reload_log(leagues)
return leagues
StartGameWithoutHumans.new]
end
- def match(players, logics)
+ def match(players, logics, options)
logics.inject(players) do |result, item|
+ item.set_options(options)
item.match(result)
result
end
end
end # class << self
+ def initialize
+ @options = {}
+ end
+
+ def set_options(options)
+ @options.merge!(options)
+ end
# Make matches among players.
# @param players an array of players, which should be updated destructively
log_message("Floodgate: Starting a game: BLACK %s vs WHITE %s" % [p1.name, p2.name])
p1.sente = true
p2.sente = false
- board = Board.new
+ board = Board.new(@options)
board.initial
Game.new(p1.game_name, p1, p2, board)
end
assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
assert_equal("yowai_gps+95908f6c18338f5340371f71523fc5e3", ntc.sacrifice)
end
+
+ def test_default_max_moves
+ now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
+ lines = %w(Thu\ 22:00)
+ ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new lines
+ assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
+ assert_equal(256, ntc.max_moves)
+ end
+
+ def test_read_max_moves
+ now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
+ lines = %w(set\ max_moves\ 200 Thu\ 22:00)
+ ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new lines
+ assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
+ assert_equal(200, ntc.max_moves)
+ end
end
V2
N+atmark_B@p1
N-atmark_W@p2
+'Max_Moves:256
+'Least_Time_Per_Move:0
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI * * * * * -KA *
P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
V2
N+hc2p_hoge_B
N-hc2p_hoge_W
+'Max_Moves:256
+'Least_Time_Per_Move:0
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI * * * * * -KA *
P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
$options = {}
$options["least-time-per-move"] = 1
+$options["max-moves"] = 0
def log_message(str)
$stderr.puts str
Your_Turn:+
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
Your_Turn:-
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
V2
N+p1
N-p2
+'Max_Moves:#{$options["max-moves"]}
+'Least_Time_Per_Move:#{$options["least-time-per-move"]}
$EVENT:#{game.game_id}
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI * * * * * -KA *
Your_Turn:+
Rematch_On_Draw:NO
To_Move:-
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
Your_Turn:-
Rematch_On_Draw:NO
To_Move:-
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
V2
N+p1
N-p2
+'Max_Moves:#{$options["max-moves"]}
+'Least_Time_Per_Move:#{$options["least-time-per-move"]}
$EVENT:#{game.game_id}
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI * * * * * -KA *
Your_Turn:+
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
Your_Turn:-
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
V2
N+p1
N-p2
+'Max_Moves:#{$options["max-moves"]}
+'Least_Time_Per_Move:#{$options["least-time-per-move"]}
$EVENT:#{game.game_id}
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI * * * * * -KA *
$options = {}
$options["least-time-per-move"] = 0
+$options["max-moves"] = 256
def log_message(str)
$stderr.puts str
Your_Turn:+
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
Your_Turn:-
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
V2
N+p1
N-p2
+'Max_Moves:#{$options["max-moves"]}
+'Least_Time_Per_Move:#{$options["least-time-per-move"]}
$EVENT:#{game.game_id}
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI * * * * * -KA *
Your_Turn:+
Rematch_On_Draw:NO
To_Move:-
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
Your_Turn:-
Rematch_On_Draw:NO
To_Move:-
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
V2
N+p1
N-p2
+'Max_Moves:#{$options["max-moves"]}
+'Least_Time_Per_Move:#{$options["least-time-per-move"]}
$EVENT:#{game.game_id}
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI * * * * * -KA *
Your_Turn:+
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
Your_Turn:-
Rematch_On_Draw:NO
To_Move:+
+Max_Moves:#{$options["max-moves"]}
BEGIN Time
Time_Unit:1sec
Total_Time:1500
V2
N+p1
N-p2
+'Max_Moves:#{$options["max-moves"]}
+'Least_Time_Per_Move:#{$options["least-time-per-move"]}
$EVENT:#{game.game_id}
P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
P2 * -HI * * * * * -KA *