with this command you can restart a new buoy game from the
previous stable position.
ex. %%FORK server-denou-14400-60+p1+p2+20130223185013 buoy_denou-14400-60
- - Note that this feature does not provice accurate thinking
- time estimate. The thinking time of the last posision is carried
- over to the new game regardless nth-move.
2012-12-30 Daigo Moriwaki <daigo at debian dot org>
# Split a moves line into an array of a move string.
# If it fails to parse the moves, it raises WrongMoves.
- # @param moves a moves line. Ex. "+776FU-3334Fu"
- # @return an array of a move string. Ex. ["+7776FU", "-3334FU"]
+ # @param moves a moves line. Ex. "+776FU-3334FU" or
+ # moves with times. Ex "+776FU,T2-3334FU,T5"
+ # @return an array of a move string. Ex. ["+7776FU", "-3334FU"] or
+ # an array of arrays. Ex. [["+7776FU","T2"], ["-3334FU", "T5"]]
#
def Board.split_moves(moves)
ret = []
- rs = moves.gsub %r{[\+\-]\d{4}\w{2}} do |s|
- ret << s
- ""
- end
- raise WrongMoves, rs unless rs.empty?
+ i=0
+ tmp = ""
+ while i<moves.size
+ if moves[i,1] == "+" ||
+ moves[i,1] == "-" ||
+ i == moves.size - 1
+ if i == moves.size - 1
+ tmp << moves[i,1]
+ end
+ unless tmp.empty?
+ a = tmp.split(",")
+ if a[0].size != 7
+ raise WrongMoves, a[0]
+ end
+ if a.size == 1 # "+7776FU"
+ ret << a[0]
+ else # "+7776FU,T2"
+ unless /^T\d+/ =~ a[1]
+ raise WrongMoves, a[1]
+ end
+ ret << a
+ end
+ tmp = ""
+ end
+ end
+ tmp << moves[i,1]
+ i += 1
+ end
return ret
end
# Set up a board starting with a position after the moves.
# Failing to parse the moves raises an ArgumentError.
- # @param moves an array of moves. ex. ["+7776FU", "-3334FU"]
+ # @param moves an array of moves. ex. ["+7776FU", "-3334FU"] or
+ # an array of arrays. ex. [["+7776FU","T2"], ["-3334FU","T5"]]
#
def set_from_moves(moves)
initial()
return :normal if moves.empty?
rt = nil
moves.each do |move|
- rt = handle_one_move(move, @teban)
+ rt = nil
+ case move
+ when Array
+ rt = handle_one_move(move[0], @teban)
+ when String
+ rt = handle_one_move(move, @teban)
+ end
raise ArgumentError, "bad moves: #{moves}" unless rt == :normal
end
@initial_moves = moves.dup
attr_reader :moves
attr_reader :owner
attr_reader :count
- attr_reader :sente_time
- attr_reader :gote_time
- def initialize(game_name, moves, owner, count, sente_time, gote_time)
+ def initialize(game_name, moves, owner, count)
raise "owner name is required" if owner && !owner.instance_of?(String)
- @game_name, @moves, @owner, @count, @sente_time, @gote_time = game_name, moves, owner, count, sente_time, gote_time
+ @game_name, @moves, @owner, @count = game_name, moves, owner, count
end
def decrement_count
end
def ==(rhs)
- return (@game_name == rhs.game_name &&
- @moves == rhs.moves &&
- @owner == rhs.owner &&
- @count == rhs.count &&
- @sente_time == rhs.sente_time &&
- @gote_time == rhs.gote_time)
+ return (@game_name == rhs.game_name &&
+ @moves == rhs.moves &&
+ @owner == rhs.owner &&
+ @count == rhs.count)
end
end
class NilBuoyGame < BuoyGame
def initialize
- super(nil, nil, nil, 0, nil, nil)
+ super(nil, nil, nil, 0)
end
end
if @db.root?(buoy_game.game_name)
# error
else
- hash = {'moves' => buoy_game.moves,
- 'owner' => buoy_game.owner,
- 'count' => buoy_game.count,
- 'sente_time' => buoy_game.sente_time,
- 'gote_time' => buoy_game.gote_time}
+ hash = {'moves' => buoy_game.moves,
+ 'owner' => buoy_game.owner,
+ 'count' => buoy_game.count}
@db[buoy_game.game_name] = hash
end
end
def update_game(buoy_game)
@db.transaction do
if @db.root?(buoy_game.game_name)
- hash = {'moves' => buoy_game.moves,
- 'owner' => buoy_game.owner,
- 'count' => buoy_game.count,
- 'sene_time' => buoy_game.sente_time,
- 'gote_time' => buoy_game.gote_time}
+ hash = {'moves' => buoy_game.moves,
+ 'owner' => buoy_game.owner,
+ 'count' => buoy_game.count}
@db[buoy_game.game_name] = hash
else
# error
@db.transaction(true) do
hash = @db[game_name]
if hash
- moves = hash['moves']
- owner = hash['owner']
- count = hash['count'].to_i
- sente_time = hash['sente_time'] ? hash['sente_time'].to_i : nil
- gote_time = hash['gote_time'] ? hash['gote_time'].to_i : nil
- return BuoyGame.new(game_name, moves, owner, count, sente_time, gote_time)
+ moves = hash['moves']
+ owner = hash['owner']
+ count = hash['count'].to_i
+ return BuoyGame.new(game_name, moves, owner, count)
else
return NilBuoyGame.new
end
return :continue
end
buoy.decrement_count(buoy_game)
- options = {:sente_time => buoy_game.sente_time,
- :gote_time => buoy_game.gote_time}
- Game::new(@player.game_name, @player, rival, board, options)
+ Game::new(@player.game_name, @player, rival, board)
end
else
klass = Login.handicapped_game_name?(@game_name) || Board
@game_name = game_name
@moves = moves
@count = count
- @sente_time = nil
- @gote_time = nil
- end
-
- # ForkCommand may call this method to set remaining time of both
- # players.
- #
- def set_initial_time(sente_time, gote_time)
- @sente_time = sente_time
- @gote_time = gote_time
end
def call
raise WrongMoves
end
- buoy_game = BuoyGame.new(@game_name, @moves, @player.name, @count, @sente_time, @gote_time)
+ buoy_game = BuoyGame.new(@game_name, @moves, @player.name, @count)
buoy.add_game(buoy_game)
@player.write_safe(sprintf("##[SETBUOY] +OK\n"))
log_info("A buoy game was created: %s by %s" % [@game_name, @player.name])
# found two players: p1 and p2
log_info("Starting a buoy game: %s with %s and %s" % [@game_name, p1.name, p2.name])
buoy.decrement_count(buoy_game)
-
- # remaining time for ForkCommand
- options = {:sente_time => buoy_game.sente_time,
- :gote_time => buoy_game.gote_time}
- game = Game::new(@game_name, p1, p2, board, options)
+ game = Game::new(@game_name, p1, p2, board)
return :continue
rescue WrongMoves => e
return :continue
end
- moves = game.read_moves
+ moves = game.read_moves # [["+7776FU","T2"],["-3334FU","T5"]]
@nth_move = moves.size - 1 unless @nth_move
if @nth_move > moves.size or @nth_move < 1
@player.write_safe(sprintf("##[ERROR] number of moves to fork is out of range: %s.\n", moves.size))
log_error "Number of moves to fork is out of range: %s [%s]" % [@nth_move, @player.name]
return :continue
end
- new_moves = moves[0...@nth_move]
-
- buoy_cmd = SetBuoyCommand.new(@str, @player, @new_buoy_game, new_moves.join(""), 1)
- buoy_cmd.set_initial_time(game.sente.mytime, game.gote.mytime)
+ new_moves_str = ""
+ moves[0...@nth_move].each do |m|
+ new_moves_str << m.join(",")
+ end
+ buoy_cmd = SetBuoyCommand.new(@str, @player, @new_buoy_game, new_moves_str, 1)
return buoy_cmd.call
end
end
end
- # options may or may not have follwing keys: :sente_time, :gote_time; they
- # are used for %%FORK command to set remaining times at the restart.
- #
- def initialize(game_name, player0, player1, board, options={})
+ def initialize(game_name, player0, player1, board)
@monitors = Array::new # array of MonitorHandler*
@game_name = game_name
if (@game_name =~ /-(\d+)-(\d+)$/)
@sente.game = self
@gote.game = self
- @last_move = @board.initial_moves.empty? ? "" : "%s,T1" % [@board.initial_moves.last]
+ @last_move = ""
+ unless @board.initial_moves.empty?
+ last_move = @board.initial_moves.last
+ case last_move
+ when Array
+ @last_move = last_move.join(",")
+ when String
+ @last_move = "%s,T1" % [last_move]
+ end
+ end
@current_turn = @board.initial_moves.size
@sente.status = "agree_waiting"
@fh.sync = true
@result = nil
- @options = options.dup
-
propose
end
attr_accessor :game_name, :total_time, :byoyomi, :sente, :gote, :game_id, :board, :current_player, :next_player, :fh, :monitors
@gote.status = "game"
@sente.write_safe(sprintf("START:%s\n", @game_id))
@gote.write_safe(sprintf("START:%s\n", @game_id))
- @sente.mytime = @options[:sente_time] || @total_time
- @gote.mytime = @options[:gote_time] || @total_time
+ @sente.mytime = @total_time
+ @gote.mytime = @total_time
@start_time = Time.now
end
unless @board.initial_moves.empty?
@fh.puts "'buoy game starting with %d moves" % [@board.initial_moves.size]
@board.initial_moves.each do |move|
- @fh.puts move
- @fh.puts "T1"
+ case move
+ when Array
+ @fh.puts move[0]
+ @fh.puts move[1]
+ when String
+ @fh.puts move
+ @fh.puts "T1"
+ end
end
end
end
end
def propose_message(sg_flag)
- time = @total_time
- if @options[:sente_time] && sg_flag == "+"
- time = @options[:sente_time]
- elsif @options[:gote_time] && sg_flag == "-"
- time = @options[:gote_time]
- end
-
str = <<EOM
BEGIN Game_Summary
Protocol_Version:1.1
To_Move:#{@board.teban ? "+" : "-"}
BEGIN Time
Time_Unit:1sec
-Total_Time:#{time}
+Total_Time:#{@total_time}
Byoyomi:#{@byoyomi}
Least_Time_Per_Move:#{Least_Time_Per_Move}
END Time
BEGIN Position
#{@board.initial_string.chomp}
-#{@board.initial_moves.collect {|m| m + ",T1"}.join("\n")}
+#{@board.initial_moves.collect do |m|
+ case m
+ when Array
+ m.join(",")
+ when String
+ m + ",T1"
+ end
+end.join("\n")}
END Position
END Game_Summary
EOM
return false
end
- # Read the .csa file and returns an array of moves.
- # ex. ["+7776FU", "-3334FU"]
+ # Read the .csa file and returns an array of moves and times.
+ # ex. [["+7776FU","T2"], ["-3334FU","T5"]]
#
def read_moves
ret = []
IO.foreach(@logfile) do |line|
if /^[\+\-]\d{4}[A-Z]{2}/ =~ line
- ret << line.chomp
+ ret << [line.chomp]
+ elsif /^T\d*/ =~ line
+ ret[-1] << line.chomp
end
end
return ret
class TestBuoyGame < Test::Unit::TestCase
def test_equal
- g1 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, nil, nil)
- g2 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, nil, nil)
- assert_equal g1, g2
- end
-
- def test_equal2
- g1 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, 10, 20)
- g2 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, 10, 20)
+ g1 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1)
+ g2 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1)
assert_equal g1, g2
end
def test_not_equal
- g1 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, nil, nil)
- g2 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 2, nil, nil)
- assert_not_equal g1, g2
- end
-
- def test_not_equal2
- g1 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, 10, 20)
- g2 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, 10, 200)
- assert_not_equal g1, g2
- end
-
- def test_not_equal3
- g1 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, 10, nil)
- g2 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, 10, 200)
+ g1 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1)
+ g2 = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 2)
assert_not_equal g1, g2
end
end
end
def test_add_game
- game = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, nil, nil)
- @buoy.add_game(game)
- assert !@buoy.is_new_game?("buoy_1234-900-0")
- game2 = @buoy.get_game(game.game_name)
- assert_equal game, game2
-
- @buoy.delete_game game
- assert @buoy.is_new_game?("buoy_1234-900-0")
- end
-
- def test_add_game2
- game = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1, 10, 20)
+ game = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 1)
@buoy.add_game(game)
assert !@buoy.is_new_game?("buoy_1234-900-0")
game2 = @buoy.get_game(game.game_name)
end
def test_update_game
- game = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 2, nil, nil)
+ game = ShogiServer::BuoyGame.new("buoy_1234-900-0", [], "p1", 2)
@buoy.add_game(game)
- g2 = ShogiServer::BuoyGame.new(game.game_name, game.moves, game.owner, game.count-1, nil, nil)
+ g2 = ShogiServer::BuoyGame.new(game.game_name, game.moves, game.owner, game.count-1)
@buoy.update_game(g2)
get = @buoy.get_game(g2.game_name)
assert !$p1.out.empty?
assert !$p2.out.empty?
buoy_game2 = @buoy.get_game("buoy_hoge-1500-0")
- assert_equal ShogiServer::BuoyGame.new("buoy_hoge-1500-0", "+7776FU", @p.name, 1, nil, nil), buoy_game2
+ assert_equal ShogiServer::BuoyGame.new("buoy_hoge-1500-0", "+7776FU", @p.name, 1), buoy_game2
end
def test_call_1
def test_call_error_duplicated_game_name
assert @buoy.is_new_game?("buoy_duplicated-1500-0")
- bg = ShogiServer::BuoyGame.new("buoy_duplicated-1500-0", ["+7776FU"], @p.name, 1, nil, nil)
+ bg = ShogiServer::BuoyGame.new("buoy_duplicated-1500-0", ["+7776FU"], @p.name, 1)
@buoy.add_game bg
assert !@buoy.is_new_game?("buoy_duplicated-1500-0")
#
class TestDeleteBuoyCommand < BaseTestBuoyCommand
def test_call
- buoy_game = ShogiServer::BuoyGame.new("buoy_testdeletebuoy-1500-0", "+7776FU", @p.name, 1, nil, nil)
+ buoy_game = ShogiServer::BuoyGame.new("buoy_testdeletebuoy-1500-0", "+7776FU", @p.name, 1)
assert @buoy.is_new_game?(buoy_game.game_name)
@buoy.add_game buoy_game
assert !@buoy.is_new_game?(buoy_game.game_name)
end
def test_call_not_exist
- buoy_game = ShogiServer::BuoyGame.new("buoy_notexist-1500-0", "+7776FU", @p.name, 1, nil, nil)
+ buoy_game = ShogiServer::BuoyGame.new("buoy_notexist-1500-0", "+7776FU", @p.name, 1)
assert @buoy.is_new_game?(buoy_game.game_name)
cmd = ShogiServer::DeleteBuoyCommand.new "%%DELETEBUOY", @p, buoy_game.game_name
rt = cmd.call
end
def test_call_another_player
- buoy_game = ShogiServer::BuoyGame.new("buoy_anotherplayer-1500-0", "+7776FU", "another_player", 1, nil, nil)
+ buoy_game = ShogiServer::BuoyGame.new("buoy_anotherplayer-1500-0", "+7776FU", "another_player", 1)
assert @buoy.is_new_game?(buoy_game.game_name)
@buoy.add_game(buoy_game)
assert !@buoy.is_new_game?(buoy_game.game_name)
#
class TestGetBuoyCountCommand < BaseTestBuoyCommand
def test_call
- buoy_game = ShogiServer::BuoyGame.new("buoy_testdeletebuoy-1500-0", "+7776FU", @p.name, 1, nil, nil)
+ buoy_game = ShogiServer::BuoyGame.new("buoy_testdeletebuoy-1500-0", "+7776FU", @p.name, 1)
assert @buoy.is_new_game?(buoy_game.game_name)
@buoy.add_game buoy_game
assert !@buoy.is_new_game?(buoy_game.game_name)
end
def test_call_not_exist
- buoy_game = ShogiServer::BuoyGame.new("buoy_notexist-1500-0", "+7776FU", @p.name, 1, nil, nil)
+ buoy_game = ShogiServer::BuoyGame.new("buoy_notexist-1500-0", "+7776FU", @p.name, 1)
assert @buoy.is_new_game?(buoy_game.game_name)
cmd = ShogiServer::GetBuoyCountCommand.new "%%GETBUOYCOUNT", @p, buoy_game.game_name
rt = cmd.call
@p1.agree
@p2.agree
sleep 1
- assert /^Total_Time:1499/ =~ @p1.message
- assert /^Total_Time:1499/ =~ @p2.message
+ assert /^Total_Time:1500/ =~ @p1.message
+ assert /^Total_Time:1500/ =~ @p2.message
@p2.move("-3334FU")
sleep 1
@p1.toryo