argvj

Reading in multidigit command line parameter


I'm learning J and have modified a tutorial into a jconsole script invoked by ./knight.j N to return as output the Knight's tour for an NxN board.

#!/usr/local/bin/j

kmoves=: 3 : 0
 t=. (>,{;~i.y) +"1/ _2]\2 1 2 _1 1 2 1 _2 _1 2 _1 _2 _2 1 _2 _1
 (*./"1 t e. i.y) <@#"1 y#.t
)

ktour=: 3 : 0
 M=. >kmoves y
 p=. k=. 0
 b=. 1 $~ *:y
 for. i.<:*:y do.
  b=. 0 k}b
  p=. p,k=. ((i.<./) +/"1 b{~j{M){j=. ({&b # ]) k{M
 end.
 assert. ~:p
 (,~y)$/:p
)

echo ktour 0".>2}.ARGV
exit''

However, I'm having difficulty in handling ARGV for numbers greater than 9. The script works correctly with single digit input:

$ ./knight.j 8
 0 25 14 23 28 49 12 31
15 22 27 50 13 30 63 48
26  1 24 29 62 59 32 11
21 16 51 58 43 56 47 60
 2 41 20 55 52 61 10 33
17 38 53 42 57 44  7 46
40  3 36 19 54  5 34  9
37 18 39  4 35  8 45  6

But fails on double digit input:

$ ./knight.j 10
|length error: kmoves
|   (*./"1 t e.i.y)<@#"1 y    #.t
   ARGV
┌─────────────────┬──────────┬──┐
│/Users/v64/.bin/j│./knight.j│10│
└─────────────────┴──────────┴──┘

It works if I separate the digits of the parameter into different arguments:

$ ./knight.j 1 0
 0 17 96 67 14 19 84 35 12 21
99 64 15 18 97 68 13 20 37 34
16  1 98 95 66 85 36 83 22 11
63 92 65 86 81 94 69 72 33 38
 2 87 90 93 76 71 82 39 10 23
91 62 53 78 89 80 75 70 73 32
44  3 88 61 52 77 40 59 24  9
47 50 45 54 79 60 27 74 31 58
 4 43 48 51  6 41 56 29  8 25
49 46  5 42 55 28  7 26 57 30
   ARGV
┌─────────────────┬──────────┬─┬─┐
│/Users/v64/.bin/j│./knight.j│1│0│
└─────────────────┴──────────┴─┴─┘

I understand conceptually why this works, but I can't figure out how to modify the script to accept "10" as a single argument.


Solution

  • Thanks for the additional information on ARGV.I think the issue is that 0 ". > 2}. ARGV is a list of length 1 when '10' is the third box and an atom with shape empty when '9' is in the third box.

      ARGV=: '/Users/v64/.bin/j';'./knight.j';'10'
       ARGV
    ┌─────────────────┬──────────┬──┐
    │/Users/v64/.bin/j│./knight.j│10│
    └─────────────────┴──────────┴──┘
         $ 0 ".>2}. ARGV      NB. 1 item list
    1
         0 ".>2}. ARGV
    10
       ARGV=: '/Users/v64/.bin/j';'./knight.j';'9'
         $ 0 ".>2}. ARGV      NB. atom with empty shape
    
         0 ".>2}. ARGV
    9
    

    You can change the shape of the '10' result by using {. on the length 1 list to make it an atom and I think you will find that your verb now works for double digits.

         ARGV=: '/Users/v64/.bin/j';'./knight.j';'10'
         ARGV
    ┌─────────────────┬──────────┬──┐
    │/Users/v64/.bin/j│./knight.j│10│
    └─────────────────┴──────────┴──┘
         $ {. 0 ".>2}. ARGV    NB. Atom with empty shape
    
         {. 0 ".>2}. ARGV
    10 
    

    I don't imagine this was the reason that you expected, but it does happen from time to time that results that look like atoms are actually 1 item lists which can result in length errors.

    Hope this helps.