Least_Time_Per_Move = 1
Login_Time = 300 # time for LOGIN
-Release = "$Name$".split[1].sub(/\A[^\d]*/, '').gsub(/_/, '.')
-Release.concat("-") if (Release == "")
-Revision = "$Revision$".gsub(/[^\.\d]/, '')
+Release = "$Id$"
+Revision = /Revision: (\d+)/.match("$Revision$")[1]
class League
charge
rescue Exception => ex
# ignore errors
- log_error("[in Floodgate's thread] #{ex}")
+ log_error("[in Floodgate's thread] #{ex} #{ex.backtrace}")
end
end
end
end
end # class Floodgate
+ #
+ # This manages those players who have their player_id.
+ # Since mk_rate mainly updates the yaml file, basically,
+ # this only reads data. But this writes some properties.
+ # TODO Such data should be facoted out to another file
+ #
+ class Persistent
+ def initialize(filename)
+ @db = YAML::Store.new(filename)
+ @db.transaction do |pstore|
+ @db['players'] ||= Hash.new
+ end
+ end
+
+ #
+ # trancaction=true means read only
+ #
+ def each_group(transaction=false)
+ @db.transaction(transaction) do
+ groups = @db["players"] || Hash.new
+ groups.each do |group, players|
+ yield group,players
+ end
+ end
+ end
+
+ def load_player(player)
+ return unless player.player_id
+
+ hash = nil
+ each_group(true) do |group, players|
+ hash = players[player.player_id]
+ break if hash
+ end
+ return unless hash
+
+ # a current user
+ player.name = hash['name']
+ player.rate = hash['rate'] || 0
+ player.modified_at = hash['last_modified']
+ player.rating_group = hash['rating_group']
+ player.win = hash['win'] || 0
+ player.loss = hash['loss'] || 0
+ player.last_game_win = hash['last_game_win'] || false
+ end
+
+ def save(player)
+ return unless player.player_id
+
+ each_group do |group, players|
+ hash = players[player.player_id]
+ if hash
+ # write only this property.
+ # the others are updated by ./mk_rate
+ hash['last_game_win'] = player.last_game_win
+ break
+ end
+ end
+ end
+
+ def get_players
+ players = []
+ each_group(true) do |group, players_hash|
+ players << players_hash.keys
+ end
+ return players.flatten.collect do |player_id|
+ p = BasicPlayer.new
+ p.player_id = player_id
+ load_player(p)
+ p
+ end
+ end
+ end # class Persistent
+
def initialize
@mutex = Mutex.new # guard @players
@games = Hash::new
def shutdown
@mutex.synchronize do
- @players.each {|a| save(a)}
+ @players.each do |name, player|
+ @persistent.save(player)
+ end
end
@floodgate.shutdown
end
# this should be called just after instanciating a League object.
def setup_players_database
- @db = YAML::Store.new(File.join(@dir, "players.yaml"))
+ filename = File.join(@dir, "players.yaml")
+ @persistent = Persistent.new(filename)
end
def add(player)
- self.load(player) if player.id
+ @persistent.load_player(player)
@mutex.synchronize do
@players[player.name] = player
end
end
def delete(player)
+ @persistent.save(player)
@mutex.synchronize do
- save(player)
@players.delete(player.name)
end
end
def reload
@mutex.synchronize do
- @players.each {|player| load(player)}
+ @players.each do |name, player|
+ @persistent.load_player(player)
+ end
end
end
return found ? found.last : nil
end
- def load(player)
- hash = search(player.id)
- return unless hash
-
- # a current user
- player.name = hash['name']
- player.rate = hash['rate'] || 0
- player.modified_at = hash['last_modified']
- player.rating_group = hash['rating_group']
- player.win = hash['win'] || 0
- player.loss = hash['loss'] || 0
- player.last_game_win = hash['last_game_win'] || false
- end
-
- def save(player)
- @db.transaction do
- break unless @db["players"]
- @db["players"].each do |group, players|
- hash = players[player.id]
- if hash
- hash['last_game_win'] = player.last_game_win
- break
- end
- end
- end
- end
-
- def search(id)
- hash = nil
- @db.transaction(true) do
- break unless @db["players"]
- @db["players"].each do |group, players|
- hash = players[id]
- break if hash
- end
- end
- hash
- end
-
def rated_players
- players = []
- @db.transaction(true) do
- break unless @db["players"]
- @db["players"].each do |group, players_hash|
- players << players_hash.keys
- end
- end
- return players.flatten.collect do |id|
- p = BasicPlayer.new
- p.id = id
- self.load(p)
- p
- end
+ return @persistent.get_players
end
end
class Login
def Login.good_login?(str)
tokens = str.split
- if (((tokens.length == 3) || ((tokens.length == 4) && tokens[3] == "x1")) &&
+ if (((tokens.length == 3) ||
+ ((tokens.length == 4) && tokens[3] == "x1")) &&
(tokens[0] == "LOGIN") &&
(good_identifier?(tokens[1])))
return true
def Login.factory(str, player)
(login, player.name, password, ext) = str.chomp.split
- if (ext)
+ if ext
return Loginx1.new(player, password)
else
return LoginCSA.new(player, password)
class BasicPlayer
def initialize
- @id = nil
+ @player_id = nil
@name = nil
@password = nil
+ @rate = 0
+ @win = 0
+ @loss = 0
@last_game_win = false
end
# Idetifier of the player in the rating system
- attr_accessor :id
+ attr_accessor :player_id
# Name of the player
attr_accessor :name
end
def rated?
- @id != nil
+ @player_id != nil
end
def last_game_win?
return @last_game_win
end
- def simple_id
+ def simple_player_id
if @trip
simple_name = @name.gsub(/@.*?$/, '')
"%s+%s" % [simple_name, @trip[0..8]]
end
##
- # Parses str in the LOGIN command, sets up @id and @trip
+ # Parses str in the LOGIN command, sets up @player_id and @trip
#
def set_password(str)
if str && !str.empty?
@password = str.strip
- @id = "%s+%s" % [@name, Digest::MD5.hexdigest(@password)]
+ @player_id = "%s+%s" % [@name, Digest::MD5.hexdigest(@password)]
else
- @id = @password = nil
+ @player_id = @password = nil
end
end
end
@game_name = ""
@mytime = 0 # set in start method also
@sente = nil
+ @socket_buffer = []
@main_thread = Thread::current
+ @mutex_write_guard = Mutex.new
end
attr_accessor :socket, :status
attr_accessor :protocol, :eol, :game, :mytime, :game_name, :sente
attr_accessor :main_thread
+ attr_reader :socket_buffer
def kill
log_message(sprintf("user %s killed", @name))
end
def write_safe(str)
- begin
- @socket.write(str)
- rescue Exception => ex
- log_error("Failed to send a message to #{@name}.")
- log_error("#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}")
- # TODO close
+ @mutex_write_guard.synchronize do
+ begin
+ if @socket.closed?
+ log_warning("%s's socket has been closed." % [@name])
+ return
+ end
+ if r = select(nil, [@socket], nil, 20)
+ r[1].first.write(str)
+ else
+ log_error("Sending a message to #{@name} timed up.")
+ end
+ rescue Exception => ex
+ log_error("Failed to send a message to #{@name}. #{ex.class}: #{ex.message}\t#{ex.backtrace[0]}")
+ end
end
end
def to_s
- if ((status == "game_waiting") ||
- (status == "start_waiting") ||
- (status == "agree_waiting") ||
- (status == "game"))
+ if ["game_waiting", "start_waiting", "agree_waiting", "game"].include?(status)
if (@sente)
return sprintf("%s %s %s %s +", @name, @protocol, @status, @game_name)
elsif (@sente == false)
end
def run(csa_1st_str=nil)
- while (csa_1st_str || (str = gets_safe(@socket, Default_Timeout)))
+ while ( csa_1st_str ||
+ str = gets_safe(@socket, (@socket_buffer.empty? ? Default_Timeout : 1)) )
+ $mutex.lock
begin
- $mutex.lock
+ if (@game && @game.turn?(self))
+ @socket_buffer << str
+ str = @socket_buffer.shift
+ end
+ log_message("%s (%s)" % [str, @socket_buffer.map {|a| String === a ? a.strip : a }.join(",")]) if $DEBUG
if (csa_1st_str)
str = csa_1st_str
return
end
str.chomp! if (str.class == String) # may be strip! ?
- log_message(str) if $DEBUG
case str
when ""
# Application-level protocol for Keep-Alive
comment = array_str.unshift("'*#{$1.toeuc}")
end
s = @game.handle_one_move(move, self)
- @game.fh.print("#{comment}\n") if (comment && !s)
+ @game.fh.print("#{Kconv.toeuc(comment.first)}\n") if (comment && comment.first && !s)
return if (s && @protocol == LoginCSA::PROTOCOL)
end
when /^%[^%]/, :timeout
players = LEAGUE.rated_players
players.sort {|a,b| b.rate <=> a.rate}.each do |p|
write_safe("##[RATING] %s \t %4d @%s\n" %
- [p.simple_id, p.rate, p.modified_at.strftime("%Y-%m-%d")])
+ [p.simple_player_id, p.rate, p.modified_at.strftime("%Y-%m-%d")])
end
write_safe("##[RATING] +OK\n")
when /^%%VERSION/
end # class
class Piece
- PROMOTE = {"FU" => "TO", "KY" => "NY", "KE" => "NK", "GI" => "NG", "KA" => "UM", "HI" => "RY"}
+ PROMOTE = {"FU" => "TO", "KY" => "NY", "KE" => "NK",
+ "GI" => "NG", "KA" => "UM", "HI" => "RY"}
def initialize(board, x, y, sente, promoted=false)
@board = board
@x = x
@gote_history = Hash::new(0)
@array = [[], [], [], [], [], [], [], [], [], []]
@move_count = 0
+ @teban = nil # black => true, white => false
end
attr_accessor :array, :sente_hands, :gote_hands, :history, :sente_history, :gote_history
attr_reader :move_count
(1..9).each do |i|
PieceFU::new(self, i, 7, true)
end
+ @teban = true
end
def have_piece?(hands, name)
@array[x0][y0].move_to(x1, y1)
end
@move_count += 1
+ @teban = @teban ? false : true
return true
end
return :illegal
end
-
if (sg == "+")
sente = true if sente == nil # deprecated
return :illegal unless sente == true # black player's move must be black
end
move_to(x0, y0, x1, y1, name, sente)
- str = to_s
update_sennichite(sente)
return :normal
end
a.push("\n")
end
- a.push("+\n")
+ a.push("%s\n" % [@teban ? "+" : "-"])
return a.join
end
end
end
def to_s
- black_name = @black.id || @black.name
- white_name = @white.id || @white.name
+ black_name = @black.player_id || @black.name
+ white_name = @white.player_id || @white.name
"%s:%s" % [black_name, white_name]
end
end
end
if (player0.sente)
- @sente = player0
- @gote = player1
+ @sente, @gote = player0, player1
else
- @sente = player1
- @gote = player0
+ @sente, @gote = player1, player0
end
- @current_player = @sente
- @next_player = @gote
-
+ @sente.socket_buffer.clear
+ @gote.socket_buffer.clear
+ @current_player, @next_player = @sente, @gote
@sente.game = self
- @gote.game = self
+ @gote.game = self
@last_move = ""
@current_turn = 0
@sente.status = "agree_waiting"
- @gote.status = "agree_waiting"
+ @gote.status = "agree_waiting"
+
+ @game_id = sprintf("%s+%s+%s+%s+%s",
+ LEAGUE.event, @game_name,
+ @sente.name, @gote.name, issue_current_time)
- @id = sprintf("%s+%s+%s+%s+%s",
- LEAGUE.event, @game_name, @sente.name, @gote.name, issue_current_time)
- @logfile = File.join(LEAGUE.dir, @id + ".csa")
+ now = Time.now
+ log_dir_name = File.join(LEAGUE.dir,
+ now.strftime("%Y"),
+ now.strftime("%m"),
+ now.strftime("%d"))
+ FileUtils.mkdir_p(log_dir_name) unless File.exist?(log_dir_name)
+ @logfile = File.join(log_dir_name, @game_id + ".csa")
- LEAGUE.games[@id] = self
+ LEAGUE.games[@game_id] = self
- log_message(sprintf("game created %s", @id))
+ log_message(sprintf("game created %s", @game_id))
@board = Board::new
@board.initial
propose
end
- attr_accessor :game_name, :total_time, :byoyomi, :sente, :gote, :id, :board, :current_player, :next_player, :fh, :monitors
+ attr_accessor :game_name, :total_time, :byoyomi, :sente, :gote, :game_id, :board, :current_player, :next_player, :fh, :monitors
attr_accessor :last_move, :current_turn
attr_reader :result
@sente.rated? && @gote.rated?
end
+ def turn?(player)
+ return player.status == "game" && @current_player == player
+ end
+
def monitoron(monitor)
@monitors.delete(monitor)
@monitors.push(monitor)
end
def reject(rejector)
- @sente.write_safe(sprintf("REJECT:%s by %s\n", @id, rejector))
- @gote.write_safe(sprintf("REJECT:%s by %s\n", @id, rejector))
+ @sente.write_safe(sprintf("REJECT:%s by %s\n", @game_id, rejector))
+ @gote.write_safe(sprintf("REJECT:%s by %s\n", @game_id, rejector))
finish
end
def kill(killer)
- if ((@sente.status == "agree_waiting") || (@sente.status == "start_waiting"))
+ if ["agree_waiting", "start_waiting"].include?(@sente.status)
reject(killer.name)
elsif (@current_player == killer)
abnormal_lose()
end
def finish
- log_message(sprintf("game finished %s", @id))
+ log_message(sprintf("game finished %s", @game_id))
@fh.printf("'$END_TIME:%s\n", Time::new.strftime("%Y/%m/%d %H:%M:%S"))
@fh.close
@gote = nil
@current_player = nil
@next_player = nil
- LEAGUE.games.delete(@id)
+ LEAGUE.games.delete(@game_id)
end
+ # class Game
def handle_one_move(str, player)
+ unless turn?(player)
+ return false if str == :timeout
+
+ @fh.puts("'Deferred %s" % [str])
+ log_warning("Deferred a move [%s] scince it is not %s 's turn." %
+ [str, player.name])
+ player.socket_buffer << str # always in the player's thread
+ return nil
+ end
+
finish_flag = true
- if (@current_player == player)
- @end_time = Time::new
- t = (@end_time - @start_time).floor
- t = Least_Time_Per_Move if (t < Least_Time_Per_Move)
-
- move_status = nil
- if ((@current_player.mytime - t <= -@byoyomi) && ((@total_time > 0) || (@byoyomi > 0)))
- status = :timeout
- elsif (str == :timeout)
- return false # time isn't expired. players aren't swapped. continue game
- else
- @current_player.mytime = @current_player.mytime - t
- if (@current_player.mytime < 0)
- @current_player.mytime = 0
- end
+ @end_time = Time::new
+ t = [(@end_time - @start_time).floor, Least_Time_Per_Move].max
+
+ move_status = nil
+ if ((@current_player.mytime - t <= -@byoyomi) &&
+ ((@total_time > 0) || (@byoyomi > 0)))
+ status = :timeout
+ elsif (str == :timeout)
+ return false # time isn't expired. players aren't swapped. continue game
+ else
+ @current_player.mytime -= t
+ if (@current_player.mytime < 0)
+ @current_player.mytime = 0
+ end
-# begin
- move_status = @board.handle_one_move(str, @sente == @current_player)
-# rescue
-# log_error("handle_one_move raise exception for #{str}")
-# move_status = :illegal
-# end
+ move_status = @board.handle_one_move(str, @sente == @current_player)
- if ((move_status == :illegal) || (move_status == :uchifuzme) || (move_status == :oute_kaihimore))
- @fh.printf("'ILLEGAL_MOVE(%s)\n", str)
- else
- if ((move_status == :normal) || (move_status == :outori) || (move_status == :sennichite) || (move_status == :oute_sennichite_sente_lose) || (move_status == :oute_sennichite_gote_lose))
- @sente.write_safe(sprintf("%s,T%d\n", str, t))
- @gote.write_safe(sprintf("%s,T%d\n", str, t))
- @fh.printf("%s\nT%d\n", str, t)
- @last_move = sprintf("%s,T%d", str, t)
- @current_turn = @current_turn + 1
- end
+ if [:illegal, :uchifuzume, :oute_kaihimore].include?(move_status)
+ @fh.printf("'ILLEGAL_MOVE(%s)\n", str)
+ else
+ if [:normal, :outori, :sennichite, :oute_sennichite_sente_lose, :oute_sennichite_gote_lose].include?(move_status)
+ # Thinking time includes network traffic
+ @sente.write_safe(sprintf("%s,T%d\n", str, t))
+ @gote.write_safe(sprintf("%s,T%d\n", str, t))
+ @fh.printf("%s\nT%d\n", str, t)
+ @last_move = sprintf("%s,T%d", str, t)
+ @current_turn += 1
+ end
- @monitors.each do |monitor|
- monitor.write_safe(show.gsub(/^/, "##[MONITOR][#{@id}] "))
- monitor.write_safe(sprintf("##[MONITOR][%s] +OK\n", @id))
- end
+ @monitors.each do |monitor|
+ monitor.write_safe(show.gsub(/^/, "##[MONITOR][#{@game_id}] "))
+ monitor.write_safe(sprintf("##[MONITOR][%s] +OK\n", @game_id))
end
end
+ end
- if (@next_player.status != "game") # rival is logout or disconnected
- abnormal_win()
- elsif (status == :timeout)
- timeout_lose()
- elsif (move_status == :illegal)
- illegal_lose()
- elsif (move_status == :kachi_win)
- kachi_win()
- elsif (move_status == :kachi_lose)
- kachi_lose()
- elsif (move_status == :toryo)
- toryo_lose()
- elsif (move_status == :outori)
- outori_win()
- elsif (move_status == :oute_sennichite_sente_lose)
- oute_sennichite_win_lose(@gote, @sente) # Sente is checking
- elsif (move_status == :oute_sennichite_gote_lose)
- oute_sennichite_win_lose(@sente, @gote) # Gote is checking
- elsif (move_status == :sennichite)
- sennichite_draw()
- elsif (move_status == :uchifuzume)
- uchifuzume_lose()
- elsif (move_status == :oute_kaihimore)
- oute_kaihimore_lose()
- else
- finish_flag = false
- end
- finish() if finish_flag
- (@current_player, @next_player) = [@next_player, @current_player]
- @start_time = Time::new
- return finish_flag
+ if (@next_player.status != "game") # rival is logout or disconnected
+ abnormal_win()
+ elsif (status == :timeout)
+ timeout_lose()
+ elsif (move_status == :illegal)
+ illegal_lose()
+ elsif (move_status == :kachi_win)
+ kachi_win()
+ elsif (move_status == :kachi_lose)
+ kachi_lose()
+ elsif (move_status == :toryo)
+ toryo_lose()
+ elsif (move_status == :outori)
+ outori_win()
+ elsif (move_status == :oute_sennichite_sente_lose)
+ oute_sennichite_win_lose(@gote, @sente) # Sente is checking
+ elsif (move_status == :oute_sennichite_gote_lose)
+ oute_sennichite_win_lose(@sente, @gote) # Gote is checking
+ elsif (move_status == :sennichite)
+ sennichite_draw()
+ elsif (move_status == :uchifuzume)
+ uchifuzume_lose()
+ elsif (move_status == :oute_kaihimore)
+ oute_kaihimore_lose()
+ else
+ finish_flag = false
end
+ finish() if finish_flag
+ @current_player, @next_player = @next_player, @current_player
+ @start_time = Time::new
+ return finish_flag
end
def abnormal_win
@result = GameResultWin.new(@current_player, @next_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] %%TORYO\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] %%TORYO\n", @game_id))
end
end
@result = GameResultWin.new(@next_player, @current_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] %%TORYO\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] %%TORYO\n", @game_id))
end
end
@result = GameResultDraw.new(@current_player, @next_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] #SENNICHITE\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] #SENNICHITE\n", @game_id))
end
end
@result = GameResultWin.new(winner, loser)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] #OUTE_SENNICHITE\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] #OUTE_SENNICHITE\n", @game_id))
end
end
@result = GameResultWin.new(@next_player, @current_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] #ILLEGAL_MOVE\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] #ILLEGAL_MOVE\n", @game_id))
end
end
@result = GameResultWin.new(@next_player, @current_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] #ILLEGAL_MOVE\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] #ILLEGAL_MOVE\n", @game_id))
end
end
@result = GameResultWin.new(@next_player, @current_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] #ILLEGAL_MOVE\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] #ILLEGAL_MOVE\n", @game_id))
end
end
@result = GameResultWin.new(@next_player, @current_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] #TIME_UP\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] #TIME_UP\n", @game_id))
end
end
@result = GameResultWin.new(@current_player, @next_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] %%KACHI\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] %%KACHI\n", @game_id))
end
end
@result = GameResultWin.new(@next_player, @current_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] %%KACHI\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] %%KACHI\n", @game_id))
end
end
@result = GameResultWin.new(@next_player, @current_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] %%TORYO\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] %%TORYO\n", @game_id))
end
end
@result = GameResultWin.new(@current_player, @next_player)
@fh.printf("'rating:#{@result.to_s}\n") if rated?
@monitors.each do |monitor|
- monitor.write_safe(sprintf("##[MONITOR][%s] #ILLEGAL_MOVE\n", @id))
+ monitor.write_safe(sprintf("##[MONITOR][%s] #ILLEGAL_MOVE\n", @game_id))
end
end
def start
- log_message(sprintf("game started %s", @id))
- @sente.write_safe(sprintf("START:%s\n", @id))
- @gote.write_safe(sprintf("START:%s\n", @id))
+ log_message(sprintf("game started %s", @game_id))
+ @sente.write_safe(sprintf("START:%s\n", @game_id))
+ @gote.write_safe(sprintf("START:%s\n", @game_id))
@sente.mytime = @total_time
@gote.mytime = @total_time
@start_time = Time::new
@fh.puts("V2")
@fh.puts("N+#{@sente.name}")
@fh.puts("N-#{@gote.name}")
- @fh.puts("$EVENT:#{@id}")
+ @fh.puts("$EVENT:#{@game_id}")
@sente.write_safe(propose_message("+"))
@gote.write_safe(propose_message("-"))
Protocol_Mode:Server
Format:Shogi 1.0
Declaration:Jishogi 1.1
-Game_ID:#{@id}
+Game_ID:#{@game_id}
Name+:#{@sente.name}
Name-:#{@gote.name}
Rematch_On_Draw:NO
Protocol_Mode:Server
Format:Shogi 1.0
Declaration:Jishogi 1.1
-Game_ID:#{@id}
+Game_ID:#{@game_id}
Name+:#{@sente.name}
Name-:#{@gote.name}
Your_Turn:#{sg_flag}
OPTIONS
--pid-file file
specify filename for logging process ID
- --daemon dir
- run as a daemon. Log files will be put in dir.
+ --daemon dir
+ run as a daemon. Log files will be put in dir.
LICENSE
this file is distributed under GPL version2 and might be compiled by Exerb
def parse_command_line
options = Hash::new
- parser = GetoptLong.new( ["--daemon", GetoptLong::REQUIRED_ARGUMENT],
- ["--pid-file", GetoptLong::REQUIRED_ARGUMENT]
- )
+ parser = GetoptLong.new(
+ ["--daemon", GetoptLong::REQUIRED_ARGUMENT],
+ ["--pid-file", GetoptLong::REQUIRED_ARGUMENT])
parser.quiet = true
begin
parser.each_option do |name, arg|
LEAGUE.add(player)
break
else
- client.write_safe("LOGIN:incorrect" + eol)
- client.write_safe("type 'LOGIN name password' or 'LOGIN name password x1'" + eol) if (str.split.length >= 4)
+ client.write("LOGIN:incorrect" + eol)
+ client.write("type 'LOGIN name password' or 'LOGIN name password x1'" + eol) if (str.split.length >= 4)
end
ensure
$mutex.unlock