OSDN Git Service

Add @move_count in Board class, which is used by Shogi Viewer CGI.
[shogi-server/shogi-server.git] / shogi-server
index 5f78607..0241938 100755 (executable)
@@ -40,6 +40,7 @@ require 'timeout'
 require 'socket'
 
 TCPSocket.do_not_reverse_lookup = true
+Thread.abort_on_exception = true
 
 
 class TCPSocket
@@ -224,7 +225,7 @@ class Player
         end
         if (@write_queue.size > Max_Write_Queue_Size)
           log_warning(sprintf("write_queue of %s is %d", @name, @write_queue.size))
-         return
+               return
         end
 
         if (@status == "finished")
@@ -241,7 +242,7 @@ class Player
               comment = array_str.unshift("'*#{$1}")
             end
             s = @game.handle_one_move(move, self)
-            @game.fh.print("#{comment}\n") if comment
+            @game.fh.print("#{comment}\n") if (comment && !s)
             return if (s && @protocol == "CSA")
           end
         when /^%[^%]/, :timeout
@@ -790,8 +791,10 @@ class Board
     @sente_history = Hash::new
     @gote_history = Hash::new
     @array = [[], [], [], [], [], [], [], [], [], []]
+    @move_count = 0
   end
   attr_accessor :array, :sente_hands, :gote_hands, :history, :sente_history, :gote_history
+  attr_reader :move_count
 
   def initial
     PieceKY::new(self, 1, 1, false)
@@ -872,6 +875,7 @@ class Board
       end
       @array[x0][y0].move_to(x1, y1)
     end
+    @move_count += 1
     return true
   end
 
@@ -998,11 +1002,21 @@ class Board
   end
 
   def good_kachi?(sente)
-    return false if (checkmated?(sente))
+    if (checkmated?(sente))
+      puts "'NG: Checkmating." if $DEBUG
+      return false 
+    end
+    
     ou = look_for_ou(sente)
-    return false if (sente && (ou.y >= 4))
-    return false if (! sente && (ou.y <= 6))
-
+    if (sente && (ou.y >= 4))
+      puts "'NG: Black's OU does not enter yet." if $DEBUG
+      return false     
+    end  
+    if (! sente && (ou.y <= 6))
+      puts "'NG: White's OU does not enter yet." if $DEBUG
+      return false 
+    end
+      
     number = 0
     point = 0
 
@@ -1029,16 +1043,27 @@ class Board
       point = point + piece.point
     end
 
-    return false if (number < 10)
+    if (number < 10)
+      puts "'NG: Piece#[%d] is too small." % [number] if $DEBUG
+      return false     
+    end  
     if (sente)
-      return false if (point < 28)
+      if (point < 28)
+        puts "'NG: Black's point#[%d] is too small." % [point] if $DEBUG
+        return false 
+      end  
     else
-      return false if (point < 27)
+      if (point < 27)
+        puts "'NG: White's point#[%d] is too small." % [point] if $DEBUG
+        return false 
+      end
     end
+
+    puts "'Good: Piece#[%d], Point[%d]." % [number, point] if $DEBUG
     return true
   end
 
-  def handle_one_move(str)
+  def handle_one_move(str, sente)
     if (str =~ /^([\+\-])(\d)(\d)(\d)(\d)([A-Z]{2})/)
       sg = $1
       x0 = $2.to_i
@@ -1047,11 +1072,6 @@ class Board
       y1 = $5.to_i
       name = $6
     elsif (str =~ /^%KACHI/)
-      if (@sente == @current_player)
-        sente = true
-      else
-        sente = false
-      end
       if (good_kachi?(sente))
         return :kachi_win
       else
@@ -1166,6 +1186,9 @@ class Board
 end
 
 class Game
+  @@mutex = Mutex.new
+  @@time  = 0
+
   def initialize(game_name, player0, player1)
     @monitors = Array::new
     @game_name = game_name
@@ -1192,16 +1215,15 @@ class Game
 
     @sente.status = "agree_waiting"
     @gote.status = "agree_waiting"
+    
     @id = sprintf("%s+%s+%s+%s+%s", 
-                  LEAGUE.event, @game_name, @sente.name, @gote.name,
-                  Time::new.strftime("%Y%m%d%H%M%S"))
+                  LEAGUE.event, @game_name, @sente.name, @gote.name, issue_current_time)
+    @logfile = @id + ".csa"
 
     LEAGUE.games[@id] = self
 
-
     log_message(sprintf("game created %s", @id))
 
-    @logfile = @id + ".csa"
     @board = Board::new
     @board.initial
     @start_time = nil
@@ -1264,7 +1286,7 @@ class Game
     finish_flag = true
     if (@current_player == player)
       @end_time = Time::new
-      t = (@end_time - @start_time).ceil
+      t = (@end_time - @start_time).floor
       t = Least_Time_Per_Move if (t < Least_Time_Per_Move)
       
       move_status = nil
@@ -1279,7 +1301,7 @@ class Game
         end
 
 #        begin
-          move_status = @board.handle_one_move(str)
+          move_status = @board.handle_one_move(str, @sente == @current_player)
 #        rescue
 #          log_error("handle_one_move raise exception for #{str}")
 #          move_status = :illegal
@@ -1525,9 +1547,10 @@ EOM
   def show()
     str0 = <<EOM
 BEGIN Game_Summary
-Protocol_Version:1.0
+Protocol_Version:1.1
 Protocol_Mode:Server
 Format:Shogi 1.0
+Declaration:Jishogi 1.1
 Game_ID:#{@id}
 Name+:#{@sente.name}
 Name-:#{@gote.name}
@@ -1544,7 +1567,6 @@ Last_Move:#{@last_move}
 Current_Turn:#{@current_turn}
 END Time
 BEGIN Position
-Jishogi_Declaration:1.1
 EOM
 
     str1 = <<EOM
@@ -1558,9 +1580,10 @@ EOM
   def propose_message(sg_flag)
     str = <<EOM
 BEGIN Game_Summary
-Protocol_Version:1.0
+Protocol_Version:1.1
 Protocol_Mode:Server
 Format:Shogi 1.0
+Declaration:Jishogi 1.1
 Game_ID:#{@id}
 Name+:#{@sente.name}
 Name-:#{@gote.name}
@@ -1574,7 +1597,6 @@ Byoyomi:#{@byoyomi}
 Least_Time_Per_Move:#{Least_Time_Per_Move}
 END Time
 BEGIN Position
-Jishogi_Declaration:1.1
 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
 P2 * -HI *  *  *  *  * -KA * 
 P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
@@ -1592,6 +1614,18 @@ END Game_Summary
 EOM
     return str
   end
+  
+  private
+  
+  def issue_current_time
+    time = Time::new.strftime("%Y%m%d%H%M%S").to_i
+    @@mutex.synchronize do
+      while time <= @@time do
+        time += 1
+      end
+      @@time = time
+    end
+  end
 end
 
 def usage
@@ -1694,8 +1728,11 @@ def mutex_watchdog(mutex, sec)
   while true
     begin
       timeout(sec) do
-        mutex.lock
-        mutex.unlock
+        begin
+          mutex.lock
+        ensure
+          mutex.unlock
+        end
       end
       sleep(sec)
     rescue TimeoutError
@@ -1708,6 +1745,7 @@ end
 def main
   $mutex = Mutex::new
   Thread::start do
+    Thread.pass
     mutex_watchdog($mutex, 10)
   end
 
@@ -1723,13 +1761,13 @@ def main
   write_pid_file($options["pid-file"]) if ($options["pid-file"])
 
 
-  Thread.abort_on_exception = true
 
   server = TCPserver.open(port)
   log_message("server started")
 
   while true
     Thread::start(server.accept) do |client|
+      Thread.pass
       client.sync = true
       player = nil
       while (str = client.gets_timeout(Login_Time))
@@ -1749,6 +1787,7 @@ def main
                 client.write_safe(sprintf("username %s is already connected%s", player.name, eol)) if (str.split.length >= 4)
                 client.close
                 Thread::exit
+                return
               end
             end
             LEAGUE.add(player)
@@ -1764,6 +1803,7 @@ def main
       if (! player)
         client.close
         Thread::exit
+        return
       end
       log_message(sprintf("user %s login", player.name))
       player.run
@@ -1772,7 +1812,7 @@ def main
         if (player.game)
           player.game.kill(player)
         end
-        player.finish
+        player.finish # socket has been closed
         LEAGUE.delete(player)
         log_message(sprintf("user %s logout", player.name))
       ensure