ファイル情報

Rev. b4af8394df436d7b273c27d245465efe3f1e51ed
サイズ 7,952 バイト
日時 2020-12-06 18:37:55
作者 Daigo Moriwaki
ログメッセージ

[shogi-server] Bump up the revision to 20201206

内容

module ShogiServer # for a namespace

  class Usi
    class << Usi
      def escape(str)
        str.gsub("/", "_").
            gsub("+", "@").
            gsub(" ", ".")
      end

      def unescape(str)
        str.gsub("_", "/").
            gsub("@", "+").
            gsub(".", " ")
      end

      # 1 -> a
      # 2 -> b
      # ...
      # 9 -> i
      def danToAlphabet(int)
        return (int+96).chr
      end

      # a -> 1
      # b -> 2
      # ...
      # i -> 9
      def alphabetToDan(s)
        if RUBY_VERSION >= "1.9.1"
          # String.bytes is incompatible:
          #  - Ruby 1.9.3 String.bytes returns Enumerator
          #  - Ruby 2.1.0 String.bytes returns [Integer]
          return s.each_byte.next-96
        else
          return s[0]-96
        end
      end

      def csaPieceToUsi(csa, sente)
        str = ""
        case csa
        when "FU"
          str = "p"
        when "KY"
          str = "l"
        when "KE"
          str = "n"
        when "GI"
          str = "s"
        when "KI"
          str = "g"
        when "KA"
          str = "b"
        when "HI"
          str = "r"
        when "OU"
          str = "k"
        when "TO"
          str = "+p"
        when "NY"
          str = "+l"
        when "NK"
          str = "+n"
        when "NG"
          str = "+s"
        when "UM"
          str = "+b"
        when "RY"
          str = "+r"
        end
        return sente ? str.upcase : str
      end

      def usiPieceToCsa(str)
        ret = ""
        case str.downcase
        when "p"
          ret = "FU"
        when "l"
          ret = "KY"
        when "n"
          ret = "KE"
        when "s"
          ret = "GI"
        when "g"
          ret = "KI"
        when "b"
          ret = "KA"
        when "r"
          ret = "HI"
        when "+p"
          ret = "TO"
        when "+l"
          ret = "NY"
        when "+n"
          ret = "NK"
        when "+s"
          ret = "NG"
        when "+b"
          ret = "UM"
        when "+r"
          ret = "RY"
        when "k"
          ret = "OU"
        end
        return ret
      end

      def moveToUsi(move)
        str = ""
        if move.is_drop?
          str += "%s*%s%s" % [csaPieceToUsi(move.name, move.sente).upcase, move.x1, danToAlphabet(move.y1)]
        else
          str += "%s%s%s%s" % [move.x0, danToAlphabet(move.y0), move.x1, danToAlphabet(move.y1)]
          str += "+" if move.promotion
        end

        return str
      end

      def usiToCsa(str, board, sente)
        ret = ""
        if str[1..1] == "*" 
          # drop
          ret += "00%s%s%s" % [str[2..2], alphabetToDan(str[3..3]), usiPieceToCsa(str[0..0])]
        else
          from_x = str[0..0]
          from_y = alphabetToDan(str[1..1])
          ret += "%s%s%s%s" % [from_x, from_y, str[2..2], alphabetToDan(str[3..3])]
          csa_piece = board.array[from_x.to_i][from_y.to_i]
          if str.size == 5 && str[4..4] == "+"
            # Promoting move
            ret += csa_piece.promoted_name
          else
            ret += csa_piece.current_name
          end
        end
        return (sente ? "+" : "-") + ret
      end
    end # class methods

    # Convert USI moves to CSA one by one from the initial position
    #
    class UsiToCsa
      attr_reader :board, :csa_moves, :usi_moves

      # Constructor
      #
      def initialize
        @board = ShogiServer::Board.new
        @board.initial
        @sente = true
        @csa_moves = []
        @usi_moves = []
      end

      def deep_copy
        return Marshal.load(Marshal.dump(self))
      end

      # Parses a usi move string and returns an array of [move_result_state,
      # csa_move_string]
      #
      def next(usi)
        usi_moves << usi
        csa = Usi.usiToCsa(usi, @board, @sente)
        state = @board.handle_one_move(csa, @sente)
        @sente = !@sente
        @csa_moves << csa
        return [state, csa]
      end

    end # class UsiToCsa

    # Convert CSA moves to USI one by one from the initial position
    #
    class CsaToUsi
      attr_reader :board, :csa_moves, :usi_moves

      # Constructor
      #
      def initialize
        @board = ShogiServer::Board.new
        @board.initial
        @sente = true
        @csa_moves = []
        @usi_moves = []
      end

      def deep_copy
        return Marshal.load(Marshal.dump(self))
      end
      
      # Parses a csa move string and returns an array of [move_result_state,
      # usi_move_string]
      #
      def next(csa)
        csa_moves << csa
        state = @board.handle_one_move(csa, @sente)
        @sente = !@sente
        usi = Usi.moveToUsi(@board.move)
        @usi_moves << usi
        return [state, usi]
      end
    end # class CsaToUsi

    def charToPiece(c)
      player = nil
      case c
      when /[A-Z]/
        player = true
      when /[a-z]/
        player = false
      end

      piece = nil
      case c.upcase
      when 'P' 
        piece = PieceFU
      when 'L' 
        piece = PieceKY
      when 'N' 
        piece = PieceKE
      when 'S' 
        piece = PieceGI
      when 'G' 
        piece = PieceKI
      when 'B' 
        piece = PieceKA
      when 'R' 
        piece = PieceHI
      when 'K' 
        piece = PieceOU
      end
      return [piece, player]
    end

    def piece2char(piece)
      s = ""
      case piece
      when PieceFU
        s = 'P'
      when PieceKY
        s = 'L'
      when PieceKE
        s = 'N'
      when PieceGI
        s = 'S'
      when PieceKI
        s = 'G'
      when PieceKA
        s = 'B'
      when PieceHI
        s = 'R'
      when PieceOU
        s = 'K'
      end
      s.downcase! if !piece.sente
      if piece.promoted
        s = "+%s" % [s]
      end
      return s
    end

    def parseBoard(word, board)
      x=9; y=1
      i = 0
      while (i < word.length)
        c = word[i,1]
        case c
        when /[a-zA-Z]/
          piece, player = charToPiece(c)
          piece.new(board, x, y, player)
          x -= 1
        when "+"
          cc = word[i+i]
          piece, player = charToPiece(cc)
          piece.new(board, x, y, player, true)
          x -= 1
          i += 1
        when /\d/
          x -= c.to_i
        when "/"
          x = 9
          y += 1
        else
          return 1
        end
        i += 1
      end
      return 0
    end

    def hands2usi(hands) 
      return "" if hands.empty?
      s = ""

      mapping = [[ShogiServer::PieceHI, "R"],
                 [ShogiServer::PieceKA, "B"],
                 [ShogiServer::PieceKI, "G"],
                 [ShogiServer::PieceGI, "S"],
                 [ShogiServer::PieceKE, "N"],
                 [ShogiServer::PieceKY, "L"],
                 [ShogiServer::PieceFU, "P"]]

      mapping.each do |klass, str|
        pieces = hands.find_all {|piece| piece.class == klass}
        unless pieces.empty?
          if pieces.size > 1 
            s += "%d" % [pieces.size]
          end
          s += str
        end
      end
      return s
    end

    # "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL b -"
    #
    def board2usi(board, turn)
      s = ""
      for y in 1..9
        skip = 0
        9.downto(1) do |x| 
          piece = board.array[x][y]
          case piece 
          when nil
            skip += 1
          when ShogiServer::Piece
            if skip > 0
              s += skip.to_s
              skip = 0
            end
            s += piece2char(piece)
          end
        end
        if skip > 0
          s += skip.to_s
        end
        s += "/" if y < 9
      end
      s += " "
      if turn
        s += "b"
      else
        s += "w"
      end
      s += " "
      if board.sente_hands.empty? && board.gote_hands.empty?
        return s += "-"
      end
      s += hands2usi(board.sente_hands).upcase
      s += hands2usi(board.gote_hands).downcase
      return s
    end

  end # class

end # module
旧リポジトリブラウザで表示