X-Git-Url: http://git.sourceforge.jp/view?p=shogi-server%2Fshogi-server.git;a=blobdiff_plain;f=shogi_server%2Fcommand.rb;h=a3b48a7409d0785faeeef41f2d2994a79949e45c;hp=ee8196593850e350bc043777a74cb186ea7a3cc3;hb=fd33baf3cba2786e693ae8d7b93d7b13636a6070;hpb=b20b024412a59d994153cf9e8ba04d2c7d603ec3 diff --git a/shogi_server/command.rb b/shogi_server/command.rb index ee81965..a3b48a7 100644 --- a/shogi_server/command.rb +++ b/shogi_server/command.rb @@ -96,6 +96,10 @@ module ShogiServer 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 @@ -112,6 +116,18 @@ module ShogiServer 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 @@ -139,6 +155,11 @@ module ShogiServer 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 @@ -283,8 +304,8 @@ module ShogiServer 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) @@ -369,10 +390,17 @@ module ShogiServer 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 @@ -448,6 +476,7 @@ module ShogiServer @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 @@ -462,14 +491,6 @@ module ShogiServer 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)) @@ -477,42 +498,18 @@ module ShogiServer 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) @@ -547,13 +544,6 @@ module ShogiServer 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" @@ -678,12 +668,17 @@ module ShogiServer 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 @@ -731,15 +726,32 @@ module ShogiServer @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]