OSDN Git Service

Refactoring
[shogi-server/shogi-server.git] / shogi-server
index b0548b5..14b2767 100755 (executable)
@@ -2,6 +2,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
+## Copyright (C) 2007 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -110,16 +111,16 @@ class League
     @players.delete(player.name)
   end
   
-  def get_player(status, game_name, sente, searcher=nil)
-    @players.each do |name, player|
-      if ((player.status == status) &&
-          (player.game_name == game_name) &&
-          ((sente == nil) || (player.sente == nil) || (player.sente == sente)) &&
-          ((searcher == nil) || (player != searcher)))
-        return player
-      end
+  def get_player(status, game_name, sente, searcher)
+    found = @players.find do |name, player|
+      (player.status == status) &&
+      (player.game_name == game_name) &&
+      ( (sente == nil) || 
+        (player.sente == nil) || 
+        (player.sente == sente) ) &&
+      (player != searcher)
     end
-    return nil
+    return found ? found.last : nil
   end
   
   def load(player)
@@ -448,7 +449,8 @@ class Player < BasicPlayer
           return
         end
         str.chomp! if (str.class == String) # may be strip! ?
-        case str
+        log_message(str) if $DEBUG
+        case str 
         when "" 
           # Application-level protocol for Keep-Alive
           # If the server gets LF, it sends back LF.
@@ -552,14 +554,6 @@ class Player < BasicPlayer
             write_safe(sprintf("##[ERROR] you are in %s status. GAME is valid in connected or game_waiting status\n", @status))
             next
           end
-          if ((my_sente_str == "*") ||
-              (my_sente_str == "+") ||
-              (my_sente_str == "-"))
-            ## ok
-          else
-            write_safe(sprintf("##[ERROR] bad game option\n"))
-            next
-          end
 
           if (my_sente_str == "*")
             rival = LEAGUE.get_player("game_waiting", game_name, nil, self) # no preference
@@ -569,7 +563,10 @@ class Player < BasicPlayer
             rival = LEAGUE.get_player("game_waiting", game_name, true, self) # rival must be sente
           else
             ## never reached
+            write_safe(sprintf("##[ERROR] bad game option\n"))
+            next
           end
+
           if (rival)
             @game_name = game_name
             if ((my_sente_str == "*") && (rival.sente == nil))
@@ -653,9 +650,9 @@ class Player < BasicPlayer
       ensure
         $mutex.unlock
       end
-    end                         # enf of while
-  end
-end
+    end # enf of while
+  end # def run
+end # class
 
 class Piece
   PROMOTE = {"FU" => "TO", "KY" => "NY", "KE" => "NK", "GI" => "NG", "KA" => "UM", "HI" => "RY"}
@@ -1035,10 +1032,10 @@ end
 class Board
   def initialize
     @sente_hands = Array::new
-    @gote_hands = Array::new
-    @history = Hash::new
-    @sente_history = Hash::new
-    @gote_history = Hash::new
+    @gote_hands  = Array::new
+    @history       = Hash::new(0)
+    @sente_history = Hash::new(0)
+    @gote_history  = Hash::new(0)
     @array = [[], [], [], [], [], [], [], [], [], []]
     @move_count = 0
   end
@@ -1215,25 +1212,44 @@ class Board
     return true
   end
 
-  def oute_sennichite?(sente)
-    if (checkmated?(! sente))
-      str = to_s
-      if (sente)
-        if (@sente_history[str] && (@sente_history[str] >= 3)) # already 3 times
-          return true
-        end
+  # @[sente|gote]_history has at least one item while the player is checking the other or 
+  # the other escapes.
+  def update_sennichite(player)
+    str = to_s
+    @history[str] += 1
+    if checkmated?(!player)
+      if (player)
+        @sente_history["dummy"] = 1  # flag to see Sente player is checking Gote player
       else
-        if (@gote_history[str] && (@gote_history[str] >= 3)) # already 3 times
-          return true
-        end
+        @gote_history["dummy"]  = 1  # flag to see Gote player is checking Sente player
+      end
+    else
+      if (player)
+        @sente_history.clear # no more continuous check
+      else
+        @gote_history.clear  # no more continuous check
       end
     end
-    return false
+    if @sente_history.size > 0  # possible for Sente's or Gote's turn
+      @sente_history[str] += 1
+    end
+    if @gote_history.size > 0   # possible for Sente's or Gote's turn
+      @gote_history[str] += 1
+    end
+  end
+
+  def oute_sennichite?(player)
+    if (@sente_history[to_s] >= 4)
+      return :oute_sennichite_sente_lose
+    elsif (@gote_history[to_s] >= 4)
+      return :oute_sennichite_gote_lose
+    else
+      return nil
+    end
   end
 
   def sennichite?(sente)
-    str = to_s
-    if (@history[str] && (@history[str] >= 3)) # already 3 times
+    if (@history[to_s] >= 4) # already 3 times
       return true
     end
     return false
@@ -1363,7 +1379,9 @@ class Board
     tmp_board = Marshal.load(Marshal.dump(self))
     return :illegal if (tmp_board.move_to(x0, y0, x1, y1, name, sente) == :illegal)
     return :oute_kaihimore if (tmp_board.checkmated?(sente))
-    return :oute_sennichite if tmp_board.oute_sennichite?(sente)
+    tmp_board.update_sennichite(sente)
+    os_result = tmp_board.oute_sennichite?(sente)
+    return os_result if os_result # :oute_sennichite_sente_lose or :oute_sennichite_gote_lose
     return :sennichite if tmp_board.sennichite?(sente)
 
     if ((x0 == 0) && (y0 == 0) && (name == "FU") && tmp_board.uchifuzume?(sente))
@@ -1373,20 +1391,7 @@ class Board
     move_to(x0, y0, x1, y1, name, sente)
     str = to_s
 
-    if (checkmated?(! sente))
-      if (sente)
-        @sente_history[str] = (@sente_history[str] || 0) + 1
-      else
-        @gote_history[str] = (@gote_history[str] || 0) + 1
-      end
-    else
-      if (sente)
-        @sente_history.clear
-      else
-        @gote_history.clear
-      end
-    end
-    @history[str] = (@history[str] || 0) + 1
+    update_sennichite(sente)
     return :normal
   end
 
@@ -1432,9 +1437,7 @@ class GameResult
   attr_reader :players, :black, :white
 
   def initialize(p1, p2)
-    @players = []
-    @players << p1
-    @players << p2
+    @players = [p1, p2]
     if p1.sente && !p2.sente
       @black, @white = p1, p2
     elsif !p1.sente && p2.sente
@@ -1595,7 +1598,7 @@ class Game
         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))
+          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)
@@ -1624,10 +1627,12 @@ class Game
         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 == :oute_sennichite)
-        oute_sennichite_lose()
       elsif (move_status == :uchifuzume)
         uchifuzume_lose()
       elsif (move_status == :oute_kaihimore)
@@ -1686,14 +1691,18 @@ class Game
     end
   end
 
-  def oute_sennichite_lose
+  def oute_sennichite_win_lose(winner, loser)
     @current_player.status = "connected"
     @next_player.status = "connected"
-    @current_player.write_safe("#OUTE_SENNICHITE\n#LOSE\n")
-    @next_player.write_safe("#OUTE_SENNICHITE\n#WIN\n")
+    loser.write_safe("#OUTE_SENNICHITE\n#LOSE\n")
+    winner.write_safe("#OUTE_SENNICHITE\n#WIN\n")
     @fh.print(@board.to_s.gsub(/^/, "\'"))
-    @fh.printf("'summary:oute_sennichite:%s lose:%s win\n", @current_player.name, @next_player.name)
-    @result = GameResultWin.new(@next_player, @current_player)
+    if loser == @current_player
+      @fh.printf("'summary:oute_sennichite:%s lose:%s win\n", @current_player.name, @next_player.name)
+    else
+      @fh.printf("'summary:oute_sennichite:%s win:%s lose\n", @current_player.name, @next_player.name)
+    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))
@@ -1825,20 +1834,20 @@ class Game
   end
 
   def propose
-    begin
-      @fh = open(@logfile, "w")
-      @fh.sync = true
+    @fh = open(@logfile, "w")
+    @fh.sync = true
 
-      @fh.printf("V2\n")
-      @fh.printf("N+%s\n", @sente.name)
-      @fh.printf("N-%s\n", @gote.name)
-      @fh.printf("$EVENT:%s\n", @id)
+    @fh.puts("V2")
+    @fh.puts("N+#{@sente.name}")
+    @fh.puts("N-#{@gote.name}")
+    @fh.puts("$EVENT:#{@id}")
 
-      @sente.write_safe(propose_message("+"))
-      @gote.write_safe(propose_message("-"))
+    @sente.write_safe(propose_message("+"))
+    @gote.write_safe(propose_message("-"))
 
-      @fh.printf("$START_TIME:%s\n", Time::new.strftime("%Y/%m/%d %H:%M:%S"))
-      @fh.print <<EOM
+    now = Time::new.strftime("%Y/%m/%d %H:%M:%S")
+    @fh.puts("$START_TIME:#{now}")
+    @fh.print <<EOM
 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
 P2 * -HI *  *  *  *  * -KA * 
 P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
@@ -1850,7 +1859,6 @@ P8 * +KA *  *  *  *  * +HI *
 P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
 +
 EOM
-    end
   end
 
   def show()
@@ -1972,6 +1980,10 @@ REVISION
 EOM
 end
 
+def log_debug(str)
+  $logger.debug(str)
+end
+
 def log_message(str)
   $logger.info(str)
 end