def at(*args)
      case args.length
      when 1
        self.at(*coordinates_for(args.first))
      when 2
        self.squares[args[0]][args[1]]
      end
    end
def at(*args)
      case args.length
      when 1
        self.at(*coordinates_for(args.first))
      when 2
        self.squares[args[0]][args[1]]
      end
    end
@param squares [<Array<Array<String>>>] the squares of the board
 @example
   PGN::Board.new(
     [
       ["R", "P", nil, nil, nil, nil, "p", "r"],
       ["N", "P", nil, nil, nil, nil, "p", "n"],
       ["B", "P", nil, nil, nil, nil, "p", "b"],
       ["Q", "P", nil, nil, nil, nil, "p", "q"],
       ["K", "P", nil, nil, nil, nil, "p", "k"],
       ["B", "P", nil, nil, nil, nil, "p", "b"],
       ["N", "P", nil, nil, nil, nil, "p", "n"],
       ["R", "P", nil, nil, nil, nil, "p", "r"],
     ]
   )

 @overload at(str)
   Looks up a piece based on the string representation of a square (e4)
   @param str [String] the square in algebraic notation
 @overload at(file, rank)
   Looks up a piece based on zero-indexed coordinates (4, 3)
   @param file [Integer] the file the piece is on
   @param rank [Integer] the rank the piece is on
 @return [String, nil] the piece on the square, or nil if it is
   empty
 @example
   board.at(4,3)  #=> "P"
   board.at("e4") #=> "P"