最近在學 Ruby,而要學一個 programming language 最快的方法就是動手去寫,可是工作之餘我又沒太多時間可以寫大一點的程式,因此我通常會找 Programming Challenges 裡面的題目來自娛。

下面的程式就是我的第一個 Ruby 程式: 解 Check The Check 這個問題:

class Chess

  @@capture =
  {
    'p' => [[-1,  1, 1], [ 1,  1, 1]],
    'P' => [[-1, -1, 1], [ 1, -1, 1]],
    'r' => [[ 1,  0, 8], [-1,  0, 8], [0,  1, 8], [ 1,  0, 8]],
    'b' => [[-1,  1, 8], [ 1,  1, 8], [1, -1, 8], [-1, -1, 8]],
    'n' => [[-2, -1, 1], [-1, -2, 1], [1, -2, 1], [ 2, -1, 1], [2, 1, 1], [1, 2, 1], [-1, -2, 1], [-2, -1, 1]],
    'k' => [[-1,  1, 1], [ 1,  1, 1], [1, -1, 1], [-1, -1, 1], [1, 0, 1], [0, 1, 1], [-1,  0, 1], [ 0, -1, 1]],
    'q' => [[-1,  1, 8], [ 1,  1, 8], [1, -1, 8], [-1, -1, 8], [1, 0, 8], [0, 1, 8], [-1,  0, 8], [ 0, -1, 8]],
  }

  @@capture.each_key {|p| @@capture[p.upcase] = @@capture[p] unless @@capture.has_key?(p.upcase)}

  def initialize
    @board = Array.new(8) { loop { line = gets.chomp.strip; break line if line.length >= 8 } }
  end

  def is_empty
    @board.select{|row| row == '.' * 8}.length == 8
  end

  def in_check
    0.upto(7) do |y|
      0.upto(7) do |x|
        piece = @board[y][x..x]
        if @@capture[piece]:
          cap = check_capture(piece, x, y)
          return cap[0] if cap.length > 0
        end
      end
    end
    "no"
  end

  def check_capture(piece, col, row)
    @@capture[piece].collect{|dir| check_dir(piece, col, row, dir)}.compact
  end

  def check_dir(piece, x, y, dir)
    dir[2].times do
      x += dir[0]
      y += dir[1]
      break if !(0..7).include?(x) or !(0..7).include?(y)
      case @board[y][x..x]
      when 'k': return 'black' if ('A'..'Z').include?(piece)
      when 'K': return 'white' if ('a'..'z').include?(piece)
      when '.': next
      else break
      end
    end
    nil
  end

end

i = 1
loop do
  c = Chess.new
  break if c.is_empty
  print "Game \##{i}: #{c.in_check} king is in check\n"
  i += 1
end

結論是:code block 實在是太好用了,會讓你走火入魔每個地方都想用一下…