module Shogi::Format::CSA::Board
Public Instance Methods
parse_from_csa(csa)
click to toggle source
# File lib/shogi/format/csa/board.rb, line 35 def parse_from_csa(csa) table = [] cell_pattern = '[+-][A-Z]{2}| \* ' csa_lines = csa.each_line.to_a csa_lines.slice(0, 9).to_enum.with_index do |row, i| table_row = [] row.chomp! unless /\AP#{i + 1}(#{cell_pattern}){9}\z/ =~ row raise FormatError, "Format Error: line P#{i + 1}" end row[2..28].scan(/#{cell_pattern}/) do |cell| if cell == " * " table_row << "" else table_row << cell end end table << table_row end captured = [] csa_lines.slice(9, 2).each do |captured_line| captured_line.chomp! unless /\AP[+-](00[A-Z]{2})*\z/ =~ captured_line raise FormatError, "Invalid format: #{captured_line}" end turn = captured_line[1] captured_line[2..-1].scan(/00([A-Z]{2})/) do |cell| captured << turn + cell[0] end end [table, captured] end
to_csa()
click to toggle source
# File lib/shogi/format/csa/board.rb, line 5 def to_csa csa_rows = "" @table.each_with_index do |row, i| csa_row = "" row.each do |cell| if cell == "" csa_row << " * " else csa_row << cell end end csa_rows << "P#{i + 1}#{csa_row}\n" end sente = "P+" gote = "P-" @captured.each do |piece| if piece[0] == "+" sente << "00#{piece[1..2]}" else gote << "00#{piece[1..2]}" end end csa_rows << "#{sente}\n" csa_rows << "#{gote}\n" csa_rows end
Private Instance Methods
move_by_csa(csa)
click to toggle source
# File lib/shogi/format/csa/board.rb, line 71 def move_by_csa(csa) unless /\A[+-](00|[1-9]{2})[1-9]{2}[A-Z]{2}\z/ =~ csa raise FormatError, "Invalid CSA format: #{csa}" end unless Piece.const_defined?(csa[5..6]) raise UndefinedPieceError, "Undefined piece: #{csa[5..6]}" end if csa[1..2] == "00" before_piece = csa[0] + csa[5..6] unless @captured.include?(before_piece) raise MoveError, "Not captured piece: #{before_piece}" end before_cell = before_piece before_piece = Piece.const_get(before_cell[1..2]).new else before_x = to_array_x_from_shogi_x(csa[1].to_i) before_y = to_array_y_from_shogi_y(csa[2].to_i) before_cell = @table[before_y][before_x] if before_cell == "" raise MoveError, "Before cell is blank" end before_piece = Piece.const_get(before_cell[1..2]).new unless csa[0] == before_cell[0] raise MoveError, "Not your piece: #{before_cell}" end unless csa[5..6] == before_cell[1..2] after_piece = Piece.const_get(csa[5..6]).new unless before_piece.promoter == after_piece.class raise MoveError, "Can't promote: #{before_cell[1..2]} -> #{csa[5..6]}" end after_y = to_array_y_from_shogi_y(csa[4].to_i) if csa[0] == "+" unless after_y < 3 || before_y < 3 raise_movement_error("Can't promote: #{csa}") end else unless after_y > 5 || before_y > 5 raise_movement_error("Can't promote: #{csa}") end end end end after_x = to_array_x_from_shogi_x(csa[3].to_i) after_y = to_array_y_from_shogi_y(csa[4].to_i) after_cell = @table[after_y][after_x] if csa[0] == after_cell[0] raise MoveError, "Your piece exists in the cell: #{csa}" end if csa[1..2] == "00" unless after_cell == "" raise MoveError, "A piece exists in the cell: #{csa}" end if csa[5..6] == "FU" (1..9).each do |y| cell = @table[to_array_y_from_shogi_y(y)][after_x] if cell[1..2] == "FU" && cell[0] == csa[0] raise_movement_error("Your FU exists in the cell of the same column: #{csa[3]}#{y}") end end end else sign = csa[0] == '+' ? 1 : -1 movement_x = (after_x - before_x) * sign movement_y = (before_y - after_y) * sign if (movement_x == 0 || movement_y == 0 || movement_x.abs == movement_y.abs) && [movement_x.abs, movement_y.abs].max >= 2 xs = (-(movement_x.abs-1)...0).map{|x| sign * (movement_x <=> 0) * x} ys = (-(movement_y.abs-1)...0).map{|x| sign * (movement_y <=> 0) * x} (xs.empty? ? [0] * ys.size : xs).zip(ys) .map{|x, y| [csa[1].to_i + (x || 0), csa[2].to_i + (y || 0)]} .each do |x, y| if (1..9).include?(x) && (1..9).include?(y) piece = @table[to_array_y_from_shogi_y(y)][to_array_x_from_shogi_x(x)] raise_movement_error("Can't jump over a piece: #{piece}") if piece && !piece.empty? end end end unless before_piece.move?(movement_x, movement_y) raise_movement_error("Invalid movement: #{csa}") end end unless after_cell == "" after_piece = Piece.const_get(after_cell[1..2]).new if after_piece.class.const_defined?(:CHILD) @captured << "#{csa[0]}#{after_piece.class::CHILD}" else @captured << "#{csa[0]}#{after_cell[1..2]}" end end @table[after_y][after_x] = "#{csa[0]}#{csa[5..6]}" if csa[1..2] == "00" used = nil @captured.each_with_index do |captured_piece, i| if captured_piece == before_cell used = @captured.delete_at(i) break end end unless used == before_cell raise CodingError, "[Bug] missing piece in captured" end else @table[before_y][before_x] = "" end self end