when /^%%GETBUOYCOUNT\s+(\S+)/
game_name = $1
cmd = GetBuoyCountCommand.new(str, player, game_name)
+ when /^%%FORK\s+(\S+)\s+(\S+)(.*)/
+ source_game = $1
+ new_buoy_game = $2
+ nth_move = nil
+ if $3 && /^\s+(\d+)/ =~ $3
+ nth_move = $3.to_i
+ end
+ cmd = ForkCommand.new(str, player, source_game, new_buoy_game, nth_move)
when /^\s*$/
cmd = SpaceCommand.new(str, player)
when /^%%%[^%]/
@command_name = command_name
@game_name = game_name
@my_sente_str = my_sente_str
+ player.set_sente_from_str(@my_sente_str)
end
def call
end
@player.sente = nil
else
- rival = $league.find_rival(@player, @my_sente_str, @game_name)
+ rival = $league.find_rival(@player, @game_name)
if rival.instance_of?(Symbol)
# An error happened. rival is not a player instance, but an error
# symobl that must be returned to the main routine immediately.
if (@command_name == "GAME")
@player.status = "game_waiting"
@player.game_name = @game_name
- @player.set_sente_from_str(@my_sente_str)
else # challenge
@player.write_safe(sprintf("##[ERROR] can't find rival for %s\n", @game_name))
@player.status = "connected"
@player.write_safe(sprintf("##[SETBUOY] +OK\n"))
log_info("A buoy game was created: %s by %s" % [@game_name, @player.name])
- # if two players, who are not @player, are waiting for a new game, start it
- p1 = $league.get_player("game_waiting", @game_name, true, @player)
- return :continue unless p1
- p2 = $league.get_player("game_waiting", @game_name, false, @player)
- return :continue unless p2
-
+ # if two players are waiting for this buoy game, start it
+ candidates = $league.find_all_players do |player|
+ player.status == "game_waiting" &&
+ player.game_name == @game_name &&
+ player.name != @player.name
+ end
+ if candidates.empty?
+ log_info("No players found for a buoy game. Wait for players: %s" % [@game_name])
+ return :continue
+ end
+ p1 = candidates.first
+ p2 = $league.find_rival(p1, @game_name)
+ if p2.nil?
+ log_info("No opponent found for a buoy game. Wait for the opponent: %s by %s" % [@game_name, p1.name])
+ return :continue
+ elsif p2.instance_of?(Symbol)
+ # An error happened. rival is not a player instance, but an error
+ # symobl that must be returned to the main routine immediately.
+ return p2
+ end
+ # 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)
game = Game::new(@game_name, p1, p2, board)
return :continue
+
rescue WrongMoves => e
@player.write_safe(sprintf("##[ERROR] wrong moves: %s\n", @moves))
log_error "Received wrong moves: %s from %s. [%s]" % [@moves, @player.name, e.message]
end
end
+ # %%FORK <source_game> <new_buoy_game> [<nth-move>]
+ # Fork a new game from the posistion where the n-th (starting from 1) move
+ # of a source game is played. The new game should be a valid buoy game
+ # name. The default value of n is the position where the previous position
+ # of the last one.
+ #
+ class ForkCommand < Command
+ def initialize(str, player, source_game, new_buoy_game, nth_move)
+ super(str, player)
+ @source_game = source_game
+ @new_buoy_game = new_buoy_game
+ @nth_move = nth_move # may be nil
+ end
+
+ def call
+ game = $league.games[@source_game]
+ unless game
+ @player.write_safe(sprintf("##[ERROR] wrong source game name: %s\n", @source_game))
+ log_error "Received a wrong source game name: %s from %s." % [@source_game, @player.name]
+ return :continue
+ end
+
+ 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_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 # module ShogiServer