cmd = GetBuoyCountCommand.new(str, player, game_name)
when /^\s*$/
cmd = SpaceCommand.new(str, player)
+ when /^%%%[^%]/
+ # TODO: just ignore commands specific to 81Dojo.
+ # Need to discuss with 81Dojo people.
+ cmd = VoidCommand.new(str, player)
else
cmd = ErrorCommand.new(str, player)
end
attr_accessor :time
end
+ # Dummy command which does nothing.
+ #
+ class VoidCommand < Command
+ def initialize(str, player)
+ super
+ end
+
+ def call
+ return :continue
+ end
+ end
+
# Application-level protocol for Keep-Alive.
# If the server receives an LF, it sends back an LF. Note that the 30 sec
# rule (client may not send LF again within 30 sec) is not implemented
if (@player.status == "game")
array_str = @str.split(",")
move = array_str.shift
+ if @player.game.last_move &&
+ @player.game.last_move.split(",").first == move
+ log_warning("Received two sequencial identical moves [#{move}] from #{@player.name}. The last one was ignored.")
+ return :continue
+ end
additional = array_str.shift
comment = nil
if /^'(.*)/ =~ additional
def ==(rhs)
return rhs != nil &&
rhs.is_a?(MonitorHandler) &&
- @player = rhs.player &&
- @type = rhs.type
+ @player == rhs.player &&
+ @type == rhs.type
end
def write_safe(game_id, str)
end
end
- class Monitor2OffCommand < MonitorOffCommand # same
+ class Monitor2OffCommand < MonitorOffCommand
def initialize(str, player, game)
super
end
+
+ def call
+ if (@game)
+ @game.monitoroff(MonitorHandler2.new(@player))
+ end
+ return :continue
+ end
end
# Command of HELP
@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
rival = nil
- if (Buoy.game_name?(@game_name))
- if (@my_sente_str != "*")
- @player.write_safe(sprintf("##[ERROR] You are not allowed to specify TEBAN %s for the game %s\n", @my_sente_str, @game_name))
- return :continue
- end
- @player.sente = nil
- end # really end
-
if (League::Floodgate.game_name?(@game_name))
if (@my_sente_str != "*")
@player.write_safe(sprintf("##[ERROR] You are not allowed to specify TEBAN %s for the game %s\n", @my_sente_str, @game_name))
end
@player.sente = nil
else
- if (@my_sente_str == "*") && !Login.handicapped_game_name?(@game_name)
- rival = $league.get_player("game_waiting", @game_name, nil, @player) # no preference
- elsif (@my_sente_str == "+")
- rival = $league.get_player("game_waiting", @game_name, false, @player) # rival must be gote
- elsif (@my_sente_str == "-")
- rival = $league.get_player("game_waiting", @game_name, true, @player) # rival must be sente
- else
- @player.write_safe(sprintf("##[ERROR] bad game option\n"))
- return :continue
+ 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.
+ return rival
end
end
if (rival)
@player.game_name = @game_name
-
- if ((@my_sente_str == "*") && (rival.sente == nil))
- if (rand(2) == 0)
- @player.sente = true
- rival.sente = false
- else
- @player.sente = false
- rival.sente = true
- end
- elsif (rival.sente == true) # rival has higher priority
- @player.sente = false
- elsif (rival.sente == false)
- @player.sente = true
- elsif (@my_sente_str == "+")
- @player.sente = true
- rival.sente = false
- elsif (@my_sente_str == "-")
- @player.sente = false
- rival.sente = true
- else
- ## never reached
- end
+ Game::decide_turns(@player, @my_sente_str, rival)
+
if (Buoy.game_name?(@game_name))
buoy = Buoy.new # TODO config
if buoy.is_new_game?(@game_name)
if (@command_name == "GAME")
@player.status = "game_waiting"
@player.game_name = @game_name
- if (@my_sente_str == "+")
- @player.sente = true
- elsif (@my_sente_str == "-")
- @player.sente = false
- else
- @player.sente = nil
- end
else # challenge
@player.write_safe(sprintf("##[ERROR] can't find rival for %s\n", @game_name))
@player.status = "connected"
class ErrorCommand < Command
def initialize(str, player)
super
+ @msg = nil
end
+ attr_reader :msg
def call
- msg = "##[ERROR] unknown command %s\n" % [@str]
- @player.write_safe(msg)
- log_error(msg)
+ cmd = @str.chomp
+ # Aim to hide a possible password
+ cmd.gsub!(/LOGIN\s*(\w+)\s+.*/i, 'LOGIN \1...')
+ @msg = "##[ERROR] unknown command %s\n" % [cmd]
+ @player.write_safe(@msg)
+ log_error(@msg)
return :continue
end
end
@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]