It took me a minute or two to spot that you had gone with the valid assumption that n would be defined as the number of rows and columns from $I(matrix) which I didn't notice, and the matrix would be square.

I've gone for an interpretation that I think is equivalent to clockwise, the result is the same: I'm going East (right), South (down), West (left), North (up), then back to East again. Heading in a direction until a dead end then changing direction. As such I have variable V to indicate direction of movement V=1 for vertical (up or down, north or south) and V=0 for horizontal (left or right, west or east). Then another variable D, D=1 indicating increase and D=-1 for decrease. When you hit a dead end change V with V='V and if V becomes 0 then D=-D. That will always spin you clockwise but without limits so you need code to spot a dead end. Also, as others have said, there's no way to know which direction to start in. If you are in the bottom left corner do you start by going right or up?

Here's my code with comments:

ClassMethod Solution(ByRef m, x, y) As %String
{
 // enforcing a decreasing spiral, 210 without comments
 // Right means change y with V=0, D=1
 // Down means change x with V=1, D=1
 // Left means change y with V=0, D=-1
 // Up means change x with V=1 ,D=-1
 //
 // first letter starts the word
 w=$p(m(x),",",y),V=0,D=1
 // mark the position so it can't be re-used
 // get the next letter from $$n, end when no letter comes back, extend the word if it does, and repeat
n(x,y)=w,l=$$q:e=3 w=w_a
 // default start position to right and clockwise
 // quit if you've tried 2 directions
 // get the letter in that direction
 // if no letter or already got then change direction clockwise
 // to change direction, if currently vertical then you won't be for the next move and vice versa
 // if you are now horizontal then change direction
n() q:$i(e)=3 "" X=V*D+x,Y='V*D+y,l=$p($g(m(X)),",",Y) l=""!$d(n(X,Y)) V='S:'D=-$$n()
 // flag any anticlockwise letter as used
 n(V*-D+x,'V*-D+y)=0,x=X,y=Y,e=0 l
}
 

Hi Robert, I had to write something similar myself about 20 years ago when we moved from DSM to Caché to deal with all those pesky &$ZLIB functions. On top of that there was the problem of variable names that exceeded 8 characters. DSM was quite happy to truncate a variable to 8 characters and work with it. For example, a variable named LONGVAR was the same variable as one named LONGVARIABLE just because the first 8 were the same. Under DSM if you SET one of them the other was also SET, but not under Caché. All of these had to be found and corrected.

In the absence of an Intersystems' prescribed method I would set up a global variable with extra information on each namespace, e.g.

^%ZSYS("NAMESPACE","SYS")="IRIS"

^%ZSYS("NAMESPACE","LIVE")="CUSTOMER PRODUCTION"

The global variable with % at the start means it can be seen from all namespaces. You can add whatever information you like to it like the difference between production and non-prod etc.

Shaved down to 174. A dubious $Find-2 to get first string length. Changed a condition in the $Select from p<c&(r<3) to r<3*c>p

ClassMethod Type(a...) As %String
{
 j=$i(r):1:a{w=$tr(a(j)," "),p=$f(w,",")-2 i=2:1:$l(w,",") c=$l($p(w,",",i)),r=$s(p=c:r,r<3*c>p:2,r#2:3,1:4),p=c$p("Constant7Increasing7Decreasing7Unsorted",7,r)
}
also fits in @Robert Barbiaux attempt

ClassMethod Type(a...) As %String
{
 i=$i(r):1:$g(a){j=1:1:$l(a(i),","){l=$l($tr($p(a(i),",",j)," ")),c=$g(c,l),r=$s(l=c:r,r<3*l>c:2,r#2:3,1:4),c=lc$p("Constant1Increasing1Decreasing1Unsorted",1,r)
}
 

ClassMethod Type(args...) As %String
{
 // no attempt made at miniturizing the code, 362 chars not including comments
 res="Constant"
 i=1:1 {
  q:'$d(args(i)) w=$tr(args(i)," ")
  p=2:1:$l(w,",") {
   a=$l($p(w,",",p)),b=$l($p(w,",",p-1))
   s d=$s(a>b:1,a<b:-1,1:0)
   d>0 res=$case(res,"Constant":"Increasing","Increasing":"Increasing",:"Unsorted")
   d<0 res=$case(res,"Constant":"Decreasing","Decreasing":"Decreasing",:"Unsorted")
   }
  }
 res
}
 

You need an interactive user's system to run this without any user interaction?

If it doesn't matter who runs it and it doesn't take any serious resources and could run unnoticed then could you set a global that is checked by some code that is regularly run by a group of users? The first interactive process that finds the global could do your $ZF for you? Say SET ^GLOBAL("RUN NOTEPAD")=$H

Then in the common piece of code L +^GLOBAL("RUN NOTEPAD"):0 I $T {S:$D(^GLOBAL("RUN NOTEPAD")) X=$ZF(-1,"C:\Windows\notepad.exe") K ^GLOBAL("RUN NOTEPAD") L -K ^GLOBAL("RUN NOTEPAD")}

Otherwise I think you need to fix the destination program so it will run in the background.

Thanks Vitaliy! That is just what I was looking for!

I suppose that underneath the code, deep down in Quote^%qcr, it may be doing the same as I'm doing, but it is unlikely to have any errors in it and it's not a wild assumption that it will do it in the most efficient way.

Alas, the few version 5 sites will have to live with my slower code

%SYS>w $zv
Cache for UNIX (IBM PowerPC/32-bit) 5.0.18 (Build 6103 + Adhoc 3626) Tue Mar 7 2006 11:55:33 EST
%SYS>W $zcvt(##CLASS(%Library.Utility).FormatString($lb("abc","DEF","",,"tesT",$lb(0))),"u")

W $ZCVT(##CLASS(%Library.Utility).FormatString($LB("abc","DEF","",,"tesT",$LB(0)
^
)),"u")
<CLASS DOES NOT EXIST>
%SYS>W $zcvt(##CLASS(%Utility).FormatString($lb("abc","DEF","",,"tesT",$lb(0))),"u")

W $ZCVT(##CLASS(%Utility).FormatString($LB("abc","DEF","",,"tesT",$LB(0))),"u")
^
<CLASS DOES NOT EXIST>