Spiral matrix: Difference between revisions
Line 2,357: | Line 2,357: | ||
<lang TSE SAL> |
<lang TSE SAL> |
||
// library: math: create: array: spiral: inwards <description></description> <version control></version control> <version>1.0.0.0. |
// library: math: create: array: spiral: inwards <description></description> <version control></version control> <version>1.0.0.0.15</version> (filenamemacro=creamasi.s) [<Program>] [<Research>] [kn, ri, mo, 31-12-2012 01:15:43] |
||
PROC PROCMathCreateArraySpiralInwards( INTEGER nI ) |
PROC PROCMathCreateArraySpiralInwards( INTEGER nI ) |
||
// e.g. PROC Main() |
// e.g. PROC Main() |
Revision as of 21:59, 31 December 2012
You are encouraged to solve this task according to the task description, using any language you may know.
Produce a spiral array. A spiral array is a square arrangement of the first N2 natural numbers, where the numbers increase sequentially as you go around the edges of the array spiralling inwards.
For example, given 5, produce this array:
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
Ada
<lang ada>-- Spiral Square with Ada.Text_Io; use Ada.Text_Io; with Ada.Integer_Text_Io; use Ada.Integer_Text_Io; with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions;
procedure Spiral_Square is
type Array_Type is array(Positive range <>, Positive range <>) of Natural; function Spiral (N : Positive) return Array_Type is Result : Array_Type(1..N, 1..N); Row : Natural := 1; Col : Natural := 1; Max_Row : Natural := N; Max_Col : Natural := N; Min_Row : Natural := 1; Min_Col : Natural := 1; begin for I in 0..N**2 - 1 loop Result(Row, Col) := I; if Row = Min_Row then Col := Col + 1; if Col > Max_Col then Col := Max_Col; Row := Row + 1; end if; elsif Col = Max_Col then Row := Row + 1; if Row > Max_Row then Row := Max_Row; Col := Col - 1; end if; elsif Row = Max_Row then Col := Col - 1; if Col < Min_Col then Col := Min_Col; Row := Row - 1; end if; elsif Col = Min_Col then Row := Row - 1; if Row = Min_Row then -- Reduce spiral Min_Row := Min_Row + 1; Max_Row := Max_Row - 1; Row := Min_Row; Min_Col := Min_Col + 1; Max_Col := Max_Col - 1; Col := Min_Col; end if; end if; end loop; return Result; end Spiral; procedure Print(Item : Array_Type) is Num_Digits : constant Float := Log(X => Float(Item'Length(1)**2), Base => 10.0); Spacing : constant Positive := Integer(Num_Digits) + 2; begin for I in Item'range(1) loop for J in Item'range(2) loop Put(Item => Item(I,J), Width => Spacing); end loop; New_Line; end loop; end Print;
begin
Print(Spiral(5));
end Spiral_Square;</lang> The following is a variant using a different algorithm (which can also be used recursively): <lang ada>function Spiral (N : Positive) return Array_Type is
Result : Array_Type (1..N, 1..N); Left : Positive := 1; Right : Positive := N; Top : Positive := 1; Bottom : Positive := N; Index : Natural := 0;
begin
while Left < Right loop for I in Left..Right - 1 loop Result (Top, I) := Index; Index := Index + 1; end loop; for J in Top..Bottom - 1 loop Result (J, Right) := Index; Index := Index + 1; end loop; for I in reverse Left + 1..Right loop Result (Bottom, I) := Index; Index := Index + 1; end loop; for J in reverse Top + 1..Bottom loop Result (J, Left) := Index; Index := Index + 1; end loop; Left := Left + 1; Right := Right - 1; Top := Top + 1; Bottom := Bottom - 1; end loop; Result (Top, Left) := Index; return Result;
end Spiral;</lang>
ALGOL 68
<lang algol68>INT empty=0;
PROC spiral = (INT n)[,]INT: (
INT dx:=1, dy:=0; # Starting increments # INT x:=0, y:=0; # Starting location # [0:n-1,0:n-1]INT my array; FOR y FROM LWB my array TO UPB my array DO FOR x FROM LWB my array TO UPB my array DO my array[x,y]:=empty OD OD; FOR i TO n**2 DO my array[x,y] := i; INT nx:=x+dx, ny:=y+dy; IF ( 0<=nx AND nx<n AND 0<=ny AND ny<n | my array[nx,ny] = empty | FALSE ) THEN x:=nx; y:=ny ELSE INT swap:=dx; dx:=-dy; dy:=swap; x+:=dx; y+:=dy FI OD; my array
);
PROC print spiral = ([,]INT my array)VOID:(
FOR y FROM LWB my array TO UPB my array DO FOR x FROM LWB my array TO UPB my array DO print(whole(my array[x,y],-3)) OD; print(new line) OD
);
print spiral(spiral(5))</lang> Output:
1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9
AutoHotkey
ahk forum: discussion <lang AutoHotkey>n := 5, dx := x := y := v := 1, dy := 0
Loop % n*n {
a_%x%_%y% := v++ nx := x+dx, ny := y+dy If (1 > nx || nx > n || 1 > ny || ny > n || a_%nx%_%ny%) t := dx, dx := -dy, dy := t x := x+dx, y := y+dy
}
Loop %n% { ; generate printout
y := A_Index ; for each row Loop %n% ; and for each column s .= a_%A_Index%_%y% "`t" ; attach stored index s .= "`n" ; row is complete
} MsgBox %s% ; show output /*
1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9
- /</lang>
BBC BASIC
<lang bbcbasic> N%=5
@%=LENSTR$(N%*N%-1)+1 BotCol%=0 : TopCol%=N%-1 BotRow%=0 : TopRow%=N%-1 DIM Matrix%(TopCol%,TopRow%) Dir%=0 : Col%=0 : Row%=0 FOR I%=0 TO N%*N%-1 Matrix%(Col%,Row%)=I% PRINT TAB(Col%*@%,Row%) I% CASE Dir% OF WHEN 0: IF Col% < TopCol% THEN Col%+=1 ELSE Dir%=1 : Row%+=1 : BotRow%+=1 WHEN 1: IF Row% < TopRow% THEN Row%+=1 ELSE Dir%=2 : Col%-=1 : TopCol%-=1 WHEN 2: IF Col% > BotCol% THEN Col%-=1 ELSE Dir%=3 : Row%-=1 : TopRow%-=1 WHEN 3: IF Row% > BotRow% THEN Row%-=1 ELSE Dir%=0 : Col%+=1 : BotCol%+=1 ENDCASE NEXT END</lang>
C
Note: program produces a matrix starting from 1 instead of 0, because task says "natural numbers". <lang c>#include <stdio.h>
- include <stdlib.h>
- define valid(i, j) 0 <= i && i < m && 0 <= j && j < n && !s[i][j]
int main(int c, char **v) { int i, j, m = 0, n = 0;
/* default size: 5 */ if (c >= 2) m = atoi(v[1]); if (c >= 3) n = atoi(v[2]); if (m <= 0) m = 5; if (n <= 0) n = m;
int **s = calloc(1, sizeof(int *) * m + sizeof(int) * m * n); s[0] = (int*)(s + m); for (i = 1; i < m; i++) s[i] = s[i - 1] + n;
int dx = 1, dy = 0, val = 0, t; for (i = j = 0; valid(i, j); i += dy, j += dx ) { for (; valid(i, j); j += dx, i += dy) s[i][j] = ++val;
j -= dx; i -= dy; t = dy; dy = dx; dx = -t; }
for (t = 2; val /= 10; t++);
for(i = 0; i < m; i++) for(j = 0; j < n || !putchar('\n'); j++) printf("%*d", t, s[i][j]);
return 0; }</lang>
C++
<lang cpp>#include <vector>
- include <memory> // for auto_ptr
- include <cmath> // for the ceil and log10 and floor functions
- include <iostream>
- include <iomanip> // for the setw function
using namespace std;
typedef vector< int > IntRow; typedef vector< IntRow > IntTable;
auto_ptr< IntTable > getSpiralArray( int dimension ) { auto_ptr< IntTable > spiralArrayPtr( new IntTable( dimension, IntRow( dimension ) ) );
int numConcentricSquares = static_cast< int >( ceil( static_cast< double >( dimension ) / 2.0 ) );
int j; int sideLen = dimension; int currNum = 0;
for ( int i = 0; i < numConcentricSquares; i++ ) { // do top side for ( j = 0; j < sideLen; j++ ) ( *spiralArrayPtr )[ i ][ i + j ] = currNum++;
// do right side for ( j = 1; j < sideLen; j++ ) ( *spiralArrayPtr )[ i + j ][ dimension - 1 - i ] = currNum++;
// do bottom side for ( j = sideLen - 2; j > -1; j-- ) ( *spiralArrayPtr )[ dimension - 1 - i ][ i + j ] = currNum++;
// do left side for ( j = sideLen - 2; j > 0; j-- ) ( *spiralArrayPtr )[ i + j ][ i ] = currNum++;
sideLen -= 2; }
return spiralArrayPtr; }
void printSpiralArray( const auto_ptr< IntTable >& spiralArrayPtr ) { size_t dimension = spiralArrayPtr->size();
int fieldWidth = static_cast< int >( floor( log10( static_cast< double >( dimension * dimension - 1 ) ) ) ) + 2;
size_t col; for ( size_t row = 0; row < dimension; row++ ) { for ( col = 0; col < dimension; col++ ) cout << setw( fieldWidth ) << ( *spiralArrayPtr )[ row ][ col ]; cout << endl; } }
int main() { printSpiralArray( getSpiralArray( 5 ) ); }</lang>
C#
Solution based on the J hints: <lang csharp>public int[,] Spiral(int n) {
int[,] result = new int[n, n];
int pos = 0; int count = n; int value = -n; int sum = -1;
do { value = -1 * value / n; for (int i = 0; i < count; i++) { sum += value; result[sum / n, sum % n] = pos++; } value *= n; count--; for (int i = 0; i < count; i++) { sum += value; result[sum / n, sum % n] = pos++; } } while (count > 0);
return result;
}
// Method to print arrays, pads numbers so they line up in columns
public void PrintArray(int[,] array) {
int n = (array.GetLength(0) * array.GetLength(1) - 1).ToString().Length + 1;
for (int i = 0; i < array.GetLength(0); i++) { for (int j = 0; j < array.GetLength(1); j++) { Console.Write(array[i, j].ToString().PadLeft(n, ' ')); } Console.WriteLine(); }
}</lang>
Clojure
Based on the J hints (almost as incomprehensible) <lang clojure>(defn spiral [n]
(let [fmt (str " ~{~<~%~," (* n 3) ":;~2d ~>~}~%") counts (cons n (mapcat #(repeat 2 %) (range (dec n) 0 -1))) ones-and-ns (mapcat #(repeat %1 %2) counts (cycle [1 n -1 (- n)]))] (->> (map vector (range 0 (* n n)) (reductions + ones-and-ns)) (sort-by second) (map first) (clojure.pprint/cl-format true fmt))))</lang>
CoffeeScript
<lang coffeescript>
- Let's say you want to arrange the first N-squared natural numbers
- in a spiral, where you fill in the numbers clockwise, starting from
- the upper left corner. This code computes the values for each x/y
- coordinate of the square. (Of course, you could precompute the values
- iteratively, but what fun is that?)
spiral_value = (x, y, n) ->
prior_legs = N: 0 E: 1 S: 2 W: 3
edge_run = (edge_offset) -> N: -> edge_offset.W - edge_offset.N E: -> edge_offset.N - edge_offset.E S: -> edge_offset.E - edge_offset.S W: -> edge_offset.S - edge_offset.W
edge_offset = N: y E: n - 1 - x S: n - 1 - y W: x min_edge_offset = n for dir of edge_offset if edge_offset[dir] < min_edge_offset min_edge_offset = edge_offset[dir] border = dir inner_square_edge = n - 2 * min_edge_offset corner_offset = n * n - inner_square_edge * inner_square_edge corner_offset += prior_legs[border] * (inner_square_edge - 1) corner_offset + edge_run(edge_offset)[border]()
spiral_matrix = (n) ->
# return a nested array expression for y in [0...n] for x in [0...n] spiral_value x, y, n
do ->
for n in [6, 7] console.log "\n----Spiral n=#{n}" console.log spiral_matrix n
</lang> output <lang> > coffee spiral.coffee
Spiral n=6
[ [ 0, 1, 2, 3, 4, 5 ],
[ 19, 20, 21, 22, 23, 6 ], [ 18, 31, 32, 33, 24, 7 ], [ 17, 30, 35, 34, 25, 8 ], [ 16, 29, 28, 27, 26, 9 ], [ 15, 14, 13, 12, 11, 10 ] ]
Spiral n=7
[ [ 0, 1, 2, 3, 4, 5, 6 ],
[ 23, 24, 25, 26, 27, 28, 7 ], [ 22, 39, 40, 41, 42, 29, 8 ], [ 21, 38, 47, 48, 43, 30, 9 ], [ 20, 37, 46, 45, 44, 31, 10 ], [ 19, 36, 35, 34, 33, 32, 11 ], [ 18, 17, 16, 15, 14, 13, 12 ] ]
</lang>
Common Lisp
<lang lisp>(defun spiral (rows columns)
(do ((N (* rows columns)) (spiral (make-array (list rows columns) :initial-element nil)) (dx 1) (dy 0) (x 0) (y 0) (i 0 (1+ i))) ((= i N) spiral) (setf (aref spiral y x) i) (let ((nx (+ x dx)) (ny (+ y dy))) (cond ((and (< -1 nx columns) (< -1 ny rows) (null (aref spiral ny nx))) (setf x nx y ny)) (t (psetf dx (- dy) dy dx) (setf x (+ x dx) y (+ y dy)))))))</lang>
> (pprint (spiral 6 6)) #2A((0 1 2 3 4 5) (19 20 21 22 23 6) (18 31 32 33 24 7) (17 30 35 34 25 8) (16 29 28 27 26 9) (15 14 13 12 11 10)) > (pprint (spiral 5 3)) #2A((0 1 2) (11 12 3) (10 13 4) (9 14 5) (8 7 6))
Recurive generation: <lang lisp>(defun spiral (m n &optional (start 1))
(let ((row (list (loop for x from 0 to (1- m) collect (+ x start))))) (if (= 1 n) row ;; first row, plus (n-1) x m spiral rotated 90 degrees (append row (map 'list #'reverse
(apply #'mapcar #'list (spiral (1- n) m (+ start m))))))))
- test
(loop for row in (spiral 4 3) do
(format t "~{~4d~^~}~%" row))</lang>
D
<lang d>void main() {
import std.stdio; enum n = 5; int[n][n] M; int pos, side = n;
foreach (i; 0 .. (n / 2 + n % 2)) { foreach (j; 0 .. side) M[i][i + j] = pos++; foreach (j; 1 .. side) M[i + j][n - 1 - i] = pos++; foreach_reverse (j; 0 .. side - 1) M[n - 1 - i][i + j] = pos++; foreach_reverse (j; 1 .. side - 1) M[i + j][i] = pos++; side -= 2; }
writefln("%(%(%2d %)\n%)", M);
}</lang>
- Output:
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
Using a generator for any rectangular array: <lang d>import std.stdio;
/// 2D spiral generator const struct Spiral {
int w, h;
int opApply(int delegate(ref int, ref int, ref int) dg) { int idx, x, y, xy, dx = 1, dy; int[] subLen = [w, h-1];
void turn() { auto t = -dy; dy = dx; dx = t; xy = 1 - xy; }
void forward(int d = 1) { x += d * dx; y += d * dy; idx += d; }
Bye: while (true) { if (subLen[xy] == 0) break; foreach (_; 0 .. subLen[xy]--) if (dg(idx, x, y)) break Bye; else forward(); forward(-1); turn(); forward(); }
return 0; }
}
int[][] spiralMatrix(int w, int h) {
auto m = new typeof(return)(h, w); foreach (value, x, y; Spiral(w, h)) m[y][x] = value; return m;
}
void main() {
foreach (r; spiralMatrix(9, 4)) writefln("%(%2d %)", r);
}</lang> Output:
0 1 2 3 4 5 6 7 8 21 22 23 24 25 26 27 28 9 20 35 34 33 32 31 30 29 10 19 18 17 16 15 14 13 12 11
E
First, some quick data types to unclutter the actual algorithm.
/** Missing scalar multiplication, but we don't need it. */
def makeVector2(x, y) {
return def vector {
to x() { return x }
to y() { return y }
to add(other) { return makeVector2(x + other.x(), y + other.y()) }
to clockwise() { return makeVector2(-y, x) }
}
}
/** Bugs: (1) The printing is specialized. (2) No bounds check on the column. */
def makeFlex2DArray(rows, cols) {
def storage := ([null] * (rows * cols)).diverge()
return def flex2DArray {
to __printOn(out) {
for y in 0..!rows {
for x in 0..!cols {
out.print(<import:java.lang.makeString>.format("%3d", [flex2DArray[y, x]]))
}
out.println()
}
}
to get(r, c) { return storage[r * cols + c] }
to put(r, c, v) { storage[r * cols + c] := v }
}
}
<lang e>def spiral(size) {
def array := makeFlex2DArray(size, size) var i := -1 # Counter of numbers to fill var p := makeVector2(0, 0) # "Position" var dp := makeVector2(1, 0) # "Velocity" # If the cell we were to fill next (even after turning) is full, we're done. while (array[p.y(), p.x()] == null) { array[p.y(), p.x()] := (i += 1) # Fill cell def next := p + dp # Look forward # If the cell we were to fill next is already full, then turn clockwise. # Gimmick: If we hit the edges of the array, by the modulo we wrap around # and see the already-filled cell on the opposite edge. if (array[next.y() %% size, next.x() %% size] != null) { dp := dp.clockwise() } # Move forward p += dp } return array
}</lang> Example: <lang e>? print(spiral(5))
0 1 2 3 4
15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8</lang>
Euphoria
<lang Euphoria>function spiral(integer dimension)
integer side, curr, curr2 sequence s s = repeat(repeat(0,dimension),dimension) side = dimension curr = 0 for i = 0 to floor(dimension/2) do for j = 1 to side-1 do s[i+1][i+j] = curr -- top curr2 = curr + side-1 s[i+j][i+side] = curr2 -- right curr2 += side-1 s[i+side][i+side-j+1] = curr2 -- bottom curr2 += side-1 s[i+side-j+1][i+1] = curr2 -- left curr += 1 end for curr = curr2 + 1 side -= 2 end for if remainder(dimension,2) then s[floor(dimension/2)+1][floor(dimension/2)+1] = curr end if return s
end function
? spiral(5)</lang>
Output:
{ {0,1,2,3,4}, {15,16,17,18,5}, {14,23,24,19,6}, {13,22,21,20,7}, {12,11,10,9,8} }
Fortran
<lang fortran>PROGRAM SPIRAL
IMPLICIT NONE INTEGER, PARAMETER :: size = 5 INTEGER :: i, x = 0, y = 1, count = size, n = 0 INTEGER :: array(size,size)
DO i = 1, count x = x + 1 array(x,y) = n n = n + 1 END DO
DO count = count - 1 DO i = 1, count y = y + 1 array(x,y) = n n = n + 1 END DO DO i = 1, count x = x - 1 array(x,y) = n n = n + 1 END DO IF (n > size*size-1) EXIT count = count - 1 DO i = 1, count y = y - 1 array(x,y) = n n = n + 1 END DO DO i = 1, count x = x + 1 array(x,y) = n n = n + 1 END DO IF (n > size*size-1) EXIT END DO DO y = 1, size DO x = 1, size WRITE (*, "(I4)", ADVANCE="NO") array (x, y) END DO WRITE (*,*) END DO
END PROGRAM SPIRAL</lang>
F#
No fancy schmancy elegance here, just putting the numbers in the right place (though I commend the elegance)... <lang fsharp>let Spiral n =
let sq = Array2D.create n n 0 // Set up an output array let nCur = ref -1 // Current value being inserted let NextN() = nCur := (!nCur+1) ; !nCur // Inc current value and return new value let Frame inset = // Create the "frame" at an offset from the outside let rangeF = [inset..(n - inset - 2)] // Range we use going forward let rangeR = [(n - inset - 1)..(-1)..(inset + 1)] // Range we use going backward rangeF |> Seq.iter (fun i -> sq.[inset,i] <- NextN()) // Top of frame rangeF |> Seq.iter (fun i -> sq.[i,n-inset-1] <- NextN()) // Right side of frame rangeR |> Seq.iter (fun i -> sq.[n-inset-1,i] <- NextN()) // Bottom of frame rangeR |> Seq.iter (fun i -> sq.[i,inset] <- NextN()) // Left side of frame [0..(n/2 - 1)] |> Seq.iter (fun i -> Frame i) // Fill in all frames if n &&& 1 = 1 then sq.[n/2,n/2] <- n*n - 1 // If n is odd, fill in the last single value sq // Return our output array</lang>
GAP
<lang gap># Spiral matrix with numbers 1 .. n2, more natural in GAP SpiralMatrix := function(n)
local i, j, k, di, dj, p, vi, vj, imin, imax, jmin, jmax; a := NullMat(n, n); vi := [ 1, 0, -1, 0 ]; vj := [ 0, 1, 0, -1 ]; imin := 0; imax := n; jmin := 1; jmax := n + 1; p := 1; di := vi[p]; dj := vj[p]; i := 1; j := 1; for k in [1 .. n*n] do a[j][i] := k; i := i + di; j := j + dj; if i < imin or i > imax or j < jmin or j > jmax then i := i - di; j := j - dj; p := RemInt(p, 4) + 1; di := vi[p]; dj := vj[p]; i := i + di; j := j + dj; if p = 1 then imax := imax - 1; elif p = 2 then jmax := jmax - 1; elif p = 3 then imin := imin + 1; else jmin := jmin + 1; fi; fi; od; return a;
end;
PrintArray(SpiralMatrix(5));
- [ [ 1, 2, 3, 4, 5 ],
- [ 16, 17, 18, 19, 6 ],
- [ 15, 24, 25, 20, 7 ],
- [ 14, 23, 22, 21, 8 ],
- [ 13, 12, 11, 10, 9 ] ]</lang>
Go
<lang go>package main
import (
"fmt" "strconv"
)
var n = 5
func main() {
if n < 1 { return } top, left, bottom, right := 0, 0, n-1, n-1 sz := n * n a := make([]int, sz) i := 0 for left < right { // work right, along top for c := left; c <= right; c++ { a[top*n+c] = i i++ } top++ // work down right side for r := top; r <= bottom; r++ { a[r*n+right] = i i++ } right-- if top == bottom { break } // work left, along bottom for c := right; c >= left; c-- { a[bottom*n+c] = i i++ } bottom-- // work up left side for r := bottom; r >= top; r-- { a[r*n+left] = i i++ } left++ } // center (last) element a[top*n+left] = i
// print w := len(strconv.Itoa(n*n - 1)) for i, e := range a { fmt.Printf("%*d ", w, e) if i%n == n-1 { fmt.Println("") } }
}</lang>
Groovy
Naive "path-walking" solution: <lang groovy>enum Direction {
East([0,1]), South([1,0]), West([0,-1]), North([-1,0]); private static _n private final stepDelta private bound private Direction(delta) { stepDelta = delta } public static setN(int n) { Direction._n = n North.bound = 0 South.bound = n-1 West.bound = 0 East.bound = n-1 } public List move(i, j) { def dir = this def newIJDir = [[i,j],stepDelta].transpose().collect { it.sum() } + dir if (((North.bound)..(South.bound)).contains(newIJDir[0]) && ((West.bound)..(East.bound)).contains(newIJDir[1])) { newIJDir } else { (++dir).move(i, j) } } public Object next() { switch (this) { case North: West.bound++; return East; case East: North.bound++; return South; case South: East.bound--; return West; case West: South.bound--; return North; } }
}
def spiralMatrix = { n ->
if (n < 1) return [] def M = (0..<n).collect { [0]*n } def i = 0 def j = 0 Direction.n = n def dir = Direction.East (0..<(n**2)).each { k -> M[i][j] = k (i,j,dir) = (k < (n**2 - 1)) \ ? dir.move(i,j) \ : [i,j,dir] } M
}</lang> Test: <lang groovy>(1..10).each { n ->
spiralMatrix(n).each { row -> row.each { printf "%5d", it } println() } println ()
}</lang> Output:
0 0 1 3 2 0 1 2 7 8 3 6 5 4 0 1 2 3 11 12 13 4 10 15 14 5 9 8 7 6 0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8 0 1 2 3 4 5 19 20 21 22 23 6 18 31 32 33 24 7 17 30 35 34 25 8 16 29 28 27 26 9 15 14 13 12 11 10 0 1 2 3 4 5 6 23 24 25 26 27 28 7 22 39 40 41 42 29 8 21 38 47 48 43 30 9 20 37 46 45 44 31 10 19 36 35 34 33 32 11 18 17 16 15 14 13 12 0 1 2 3 4 5 6 7 27 28 29 30 31 32 33 8 26 47 48 49 50 51 34 9 25 46 59 60 61 52 35 10 24 45 58 63 62 53 36 11 23 44 57 56 55 54 37 12 22 43 42 41 40 39 38 13 21 20 19 18 17 16 15 14 0 1 2 3 4 5 6 7 8 31 32 33 34 35 36 37 38 9 30 55 56 57 58 59 60 39 10 29 54 71 72 73 74 61 40 11 28 53 70 79 80 75 62 41 12 27 52 69 78 77 76 63 42 13 26 51 68 67 66 65 64 43 14 25 50 49 48 47 46 45 44 15 24 23 22 21 20 19 18 17 16 0 1 2 3 4 5 6 7 8 9 35 36 37 38 39 40 41 42 43 10 34 63 64 65 66 67 68 69 44 11 33 62 83 84 85 86 87 70 45 12 32 61 82 95 96 97 88 71 46 13 31 60 81 94 99 98 89 72 47 14 30 59 80 93 92 91 90 73 48 15 29 58 79 78 77 76 75 74 49 16 28 57 56 55 54 53 52 51 50 17 27 26 25 24 23 22 21 20 19 18
Haskell
Solution based on the J hints: <lang haskell>module Spiral where
import Data.List import Control.Monad import Control.Monad.Instances
grade xs = map snd. sort $ zip xs [0..] values n = cycle [1,n,-1,-n] counts n = (n:).concatMap (ap (:) return) $ [n-1,n-2..1] reshape n = unfoldr (\xs -> if null xs then Nothing else Just (splitAt n xs))
spiral n = reshape n . grade. scanl1 (+). concat $ zipWith replicate (counts n) (values n)</lang>
Icon and Unicon
At first I looked at keeping the filling of the matrix on track using /M[r,c] which fails when out of bounds or if the cell is null, but then I noticed the progression of the row and column increments from corner to corner reminded me of sines and cosines. I'm not sure if the use of a trigonometric function counts as elegance, perversity, or both. The generator could be easily modified to start at an arbitrary corner. Or count down to produce and evolute. <lang Icon>procedure main(A) # spiral matrix N := 0 < integer(\A[1]|5) # N=1... (dfeault 5) WriteMatrix(SpiralMatrix(N)) end
procedure WriteMatrix(M) #: write the matrix every x := M[r := 1 to *M, c := 1 to *M[r]] do
writes(right(\x|"-", 3), if c = *M[r] then "\n" else "")
return end
procedure SpiralMatrix(N) #: create spiral matrix every (!(M := list(N))):= list(N) # build empty matrix NxN
# setup before starting first turn
corner := 0 # . corner we're at i := -1 # . cell contents r:= 1 ; c :=0 # . row & col cincr := integer(sin(0)) # . column incr
until i > N^2 do {
rincr := cincr # row incr follows col cincr := integer(sin(&pi/2*(corner+:=1))) # col incr at each corner if (run := N-corner/2) = 0 then break # shorten run to 0 at U/R & L/L every run to 1 by -1 do M[r +:= rincr,c +:= cincr] := i +:= 1 # move, count, and fill }
return M end</lang>
Output:
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
J
This function is the result of some beautiful insights: <lang j>spiral =. ,~ $ [: /: }.@(2 # >:@i.@-) +/\@# <:@+: $ (, -)@(1&,)
spiral 5 0 1 2 3 4
15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8</lang> Would you like some hints that will allow you to reimplement it in another language?
These inward spiralling arrays are known as "involutes"; we can also generate outward-spiraling "evolutes", and we can start or end the spiral at any corner, and go in either direction (clockwise or counterclockwise). See the first link (to JSoftware.com).
Java
<lang java5>public class Blah {
public static void main(String[] args) { print2dArray(getSpiralArray(5)); }
public static int[][] getSpiralArray(int dimension) { int[][] spiralArray = new int[dimension][dimension];
int numConcentricSquares = (int) Math.ceil((dimension) / 2.0);
int j; int sideLen = dimension; int currNum = 0;
for (int i = 0; i < numConcentricSquares; i++) { // do top side for (j = 0; j < sideLen; j++) { spiralArray[i][i + j] = currNum++; }
// do right side for (j = 1; j < sideLen; j++) { spiralArray[i + j][dimension - 1 - i] = currNum++; }
// do bottom side for (j = sideLen - 2; j > -1; j--) { spiralArray[dimension - 1 - i][i + j] = currNum++; }
// do left side for (j = sideLen - 2; j > 0; j--) { spiralArray[i + j][i] = currNum++; }
sideLen -= 2; }
return spiralArray; }
public static void print2dArray(int[][] array) { for (int[] row : array) { for (int elem : row) { System.out.printf("%3d", elem); } System.out.println(); } }
}</lang> Output:
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
JavaScript
<lang javascript>spiralArray = function (edge) {
var arr = Array(edge), x = 0, y = edge, total = edge * edge--, dx = 1, dy = 0, i = 0, j = 0; while (y) arr[--y] = []; while (i < total) { arr[y][x] = i++; x += dx; y += dy; if (++j == edge) { if (dy < 0) {x++; y++; edge -= 2} j = dx; dx = -dy; dy = j; j = 0; } } return arr;
}
// T E S T: arr = spiralArray(edge = 5); for (y= 0; y < edge; y++) console.log(arr[y].join(" ")); </lang> output
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
Liberty BASIC
Extended to include automatic scaling of the display scale and font. See spiralM5 <lang lb>nomainwin
UpperLeftX = 50 UpperLeftY = 50 WindowWidth =900 WindowHeight =930
statictext #w.st, "", 10, 850, 870, 40
open "Spiral matrix" for graphics_nsb_nf as #w
- w "trapclose [quit]"
- w "backcolor darkblue; color cyan; fill darkblue"
for N =2 to 50
#w.st "!font courier_new "; int( 60 /N); " bold" #w "down; font arial "; int( 240 /N); " bold"
g$ ="ruld" ' direction sequence if N/2 =int( N/2) then pg =2 else pg =0 ' pointer to current direction ' last move is left or right depending on N even/odd d$ =""
for i =1 to N -1 ' calculate direction to move d$ =nChar$( i, mid$( g$, pg +1, 1)) +d$ pg =( pg +1) mod 4 d$ =nChar$( i, mid$( g$, pg +1, 1)) +d$ pg =( pg +1) mod 4 next i
d$ =nChar$( N -1, "r") +d$ ' first row
#w.st " N ="; N; " "; d$
xp =60 +250 /N yp =80 +250 /N
stp =int( 750 /N)
for i =0 to N^2 -1 dir$ =mid$( d$, i, 1) select case dir$ case "r" xp =xp +stp case "d" yp =yp +stp case "l" xp =xp -stp case "u" yp =yp -stp end select
#w "place "; xp; " "; yp #w "\"; i next i
timer 3000, [on] wait [on] timer 0 #w "cls" scan
next N
wait
function nChar$( n, i$)
for i =1 to n nChar$ =nChar$ +i$ next i
end function
[quit] close #w end</lang>
Lua
<lang lua>av, sn = math.abs, function(s) return s~=0 and s/av(s) or 0 end function sindex(y, x) -- returns the value at (x, y) in a spiral that starts at 1 and goes outwards
if y == -x and y >= x then return (2*y+1)^2 end local l = math.max(av(y), av(x)) return (2*l-1)^2+4*l+2*l*sn(x+y)+sn(y^2-x^2)*(l-(av(y)==l and sn(y)*x or sn(x)*y)) -- OH GOD WHAT
end
function spiralt(side)
local ret, start, stop = {}, math.floor((-side+1)/2), math.floor((side-1)/2) for i = 1, side do ret[i] = {} for j = 1, side do ret[i][j] = side^2 - sindex(stop - i + 1,start + j - 1) --moves the coordinates so (0,0) is at the center of the spiral end end return ret
end
for i,v in ipairs(spiralt(8)) do for j, u in ipairs(v) do io.write(u .. " ") end print() end</lang>
Mathematica
We split the task up in 2 functions, one that adds a 'ring' around a present matrix. And a function that adds rings to a 'core': <lang Mathematica>AddSquareRing[x_List/;Equal@@Dimensions[x] && Length[Dimensions[x]]==2]:=Module[{new=x,size,smallest},
size=Length[x]; smallest=x1,1; Do[ newi=Prepend[newi,smallest-i]; newi=Append[newi,smallest-3 size+i-3] ,{i,size}]; PrependTo[new,Range[smallest-3size-3-size-1,smallest-3size-3]]; AppendTo[new,Range[smallest-size-1,smallest-size-size-2,-1]]; new
] MakeSquareSpiral[size_Integer/;size>0]:=Module[{largest,start,times},
start=size^2+If[Mod[size,2]==0,{{-4,-3},{-1,-2}},Template:-1]; times=If[Mod[size,2]==0,size/2-1,(size-1)/2]; Nest[AddSquareRing,start,times]
]</lang> Examples: <lang Mathematica>MakeSquareSpiral[2] // MatrixForm MakeSquareSpiral[7] // MatrixForm</lang> gives back:
MATLAB
There already exists a command to generate a spiral matrix in MATLAB. But, it creates a matrix that spirals outward, not inward like the task specification requires. It turns out that these matrices can be transformed into each other using some pretty simple transformations.
We start with a simple linear transformation: Then depending on if n is odd or even we use either an up/down or left/right mirror transformation. <lang MATLAB>function matrix = reverseSpiral(n)
matrix = (-spiral(n))+n^2; if mod(n,2)==0 matrix = flipud(matrix); else matrix = fliplr(matrix); end
end %reverseSpiral</lang> Sample Usage: <lang MATLAB>>> reverseSpiral(5)
ans =
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8</lang>
Maxima
<lang maxima>spiral(n) := block([a, i, j, k, p, di, dj, vi, vj, imin, imax, jmin, jmax], a: zeromatrix(n, n), vi: [1, 0, -1, 0], vj: [0, 1, 0, -1], imin: 0, imax: n, jmin: 1, jmax: n + 1, p: 1, di: vi[p], dj: vj[p], i: 1, j: 1, for k from 1 thru n*n do (
a[j, i]: k, i: i + di, j: j + dj, if i < imin or i > imax or j < jmin or j > jmax then ( i: i - di, j: j - dj, p: mod(p, 4) + 1, di: vi[p], dj: vj[p], i: i + di, j: j + dj, if p = 1 then imax: imax - 1 elseif p = 2 then jmax: jmax - 1 elseif p = 3 then imin: imin + 1 else jmin: jmin + 1 )
), a )$
spiral(5); /* matrix([ 1, 2, 3, 4, 5],
[16, 17, 18, 19, 6], [15, 24, 25, 20, 7], [14, 23, 22, 21, 8], [13, 12, 11, 10, 9]) */</lang>
NetRexx
<lang NetRexx>/* NetRexx */ options replace format comments java crossref symbols binary
parse arg size .
if \size.datatype('W') then do
printArray(generateArray(3)) say printArray(generateArray(4)) say printArray(generateArray(5)) say end
else do
printArray(generateArray(size)) say end
return
-- ----------------------------------------------------------------------------- method generateArray(dimension = int) private static returns int[,]
-- the output array array = int[dimension, dimension] -- get the number of squares, including the center one if -- the dimension is odd
squares = dimension % 2 + dimension // 2
-- length of a side for the current square sidelength = dimension current = 0
loop i_ = 0 to squares - 1
-- do each side of the current square -- top side loop j_ = 0 to sidelength - 1 array[i_, i_ + j_] = current current = current + 1 end j_
-- down the right side loop j_ = 1 to sidelength - 1 array[i_ + j_, dimension - 1 - i_] = current current = current + 1 end j_
-- across the bottom loop j_ = sidelength - 2 to 0 by -1 array[dimension - 1 - i_, i_ + j_] = current current = current + 1 end j_
-- and up the left side loop j_ = sidelength - 2 to 1 by -1 array[i_ + j_, i_] = current current = current + 1 end j_
-- reduce the length of the side by two rows sidelength = sidelength - 2 end i_
return array
-- ----------------------------------------------------------------------------- method printArray(array = int[,]) private static
dimension = array[1].length rl = formatSize(array) loop i_ = 0 to dimension - 1 line = Rexx("|") loop j_ = 0 to dimension - 1 line = line Rexx(array[i_, j_]).right(rl) end j_ line = line "|" say line end i_
return
-- ----------------------------------------------------------------------------- method formatSize(array = int[,]) private static returns Rexx
dim = array[1].length maxNum = Rexx(dim * dim - 1).length()
return maxNum
</lang>
- Output
| 0 1 2 | | 7 8 3 | | 6 5 4 | | 0 1 2 3 | | 11 12 13 4 | | 10 15 14 5 | | 9 8 7 6 | | 0 1 2 3 4 | | 15 16 17 18 5 | | 14 23 24 19 6 | | 13 22 21 20 7 | | 12 11 10 9 8 |
OCaml
<lang ocaml>let next_dir = function
| 1, 0 -> 0, -1 | 0, 1 -> 1, 0 | -1, 0 -> 0, 1 | 0, -1 -> -1, 0 | _ -> assert false
let next_pos ~pos:(x,y) ~dir:(nx,ny) = (x+nx, y+ny)
let next_cell ar ~pos:(x,y) ~dir:(nx,ny) =
try ar.(x+nx).(y+ny) with _ -> -2
let for_loop n init fn =
let rec aux i v = if i < n then aux (i+1) (fn i v) in aux 0 init
let spiral ~n =
let ar = Array.make_matrix n n (-1) in let pos = 0, 0 in let dir = 0, 1 in let set (x, y) i = ar.(x).(y) <- i in let step (pos, dir) = match next_cell ar pos dir with | -1 -> (next_pos pos dir, dir) | _ -> let dir = next_dir dir in (next_pos pos dir, dir) in for_loop (n*n) (pos, dir) (fun i (pos, dir) -> set pos i; step (pos, dir)); (ar)
let print =
Array.iter (fun line -> Array.iter (Printf.printf " %2d") line; print_newline())
let () = print(spiral 5)</lang>
Another implementation: <lang ocaml>let spiral n =
let ar = Array.make_matrix n n (-1) in let out i = i < 0 || i >= n in let too_far (x,y) = out x || out y || ar.(x).(y) >= 0 in let step x y (dx,dy) = (x+dx,y+dy) in let turn (i,j) = (j,-i) in let rec iter (x,y) d i = ar.(x).(y) <- i; if i < n*n-1 then let d' = if too_far (step x y d) then turn d else d in iter (step x y d') d' (i+1) in (iter (0,0) (0,1) 0; ar)
let show =
Array.iter (fun v -> Array.iter (Printf.printf " %2d") v; print_newline())
let _ = show (spiral 5)</lang>
Octave
The function make_spiral
(and helper functions) are modelled after the J solution.
<lang octave>function rs = runsum(v)
for i = 1:numel(v) rs(i) = sum(v(1:i)); endfor
endfunction
function g = grade(v)
for i = 1:numel(v) g(v(i)+1) = i-1; endfor
endfunction
function spiral = make_spiral(spirald)
series = ones(1,spirald^2); l = spirald-1; p = spirald+1; s = 1; while(l>0) series(p:p+l-1) *= spirald*s; series(p+l:p+l*2-1) *= -s; p += l*2; l--; s *= -1; endwhile series(1) = 0; spiral = reshape(grade(runsum(series)), spirald, spirald)';
endfunction
make_spiral(5)</lang>
Opal
Recursive functional solution <lang opal>IMPLEMENTATION Spiral
IMPORT Nat COMPLETELY IMPORT Seq COMPLETELY
DATA matrix == node(x:nat, y:nat, val:nat)
FUN spiral: nat -> seq[matrix] DEF spiral(size) == </lang>
ooRexx
<lang ooRexx> call printArray generateArray(3) say call printArray generateArray(4) say call printArray generateArray(5)
- routine generateArray
use arg dimension -- the output array array = .array~new(dimension, dimension)
-- get the number of squares, including the center one if -- the dimension is odd squares = dimension % 2 + dimension // 2 -- length of a side for the current square sidelength = dimension current = 0 loop i = 1 to squares -- do each side of the current square -- top side loop j = 0 to sidelength - 1 array[i, i + j] = current current += 1 end -- down the right side loop j = 1 to sidelength - 1 array[i + j, dimension - i + 1] = current current += 1 end -- across the bottom loop j = sidelength - 2 to 0 by -1 array[dimension - i + 1, i + j] = current current += 1 end -- and up the left side loop j = sidelength - 2 to 1 by -1 array[i + j, i] = current current += 1 end -- reduce the length of the side by two rows sidelength -= 2 end return array
- routine printArray
use arg array dimension = array~dimension(1) loop i = 1 to dimension line = "|" loop j = 1 to dimension line = line array[i, j]~right(2) end line = line "|" say line end
</lang> Output:
| 0 1 2 | | 7 8 3 | | 6 5 4 | | 0 1 2 3 | | 11 12 13 4 | | 10 15 14 5 | | 9 8 7 6 | | 0 1 2 3 4 | | 15 16 17 18 5 | | 14 23 24 19 6 | | 13 22 21 20 7 | | 12 11 10 9 8 |
Oz
Simple, recursive solution: <lang oz>declare
fun {Spiral N} %% create nested array Arr = {Array.new 1 N unit} for Y in 1..N do Arr.Y := {Array.new 1 N 0} end %% fill it recursively with increasing numbers C = {Counter 0} in {Fill Arr 1 N C} Arr end
proc {Fill Arr S E C} %% go right for X in S..E do Arr.S.X := {C} end %% go down for Y in S+1..E do Arr.Y.E := {C} end %% go left for X in E-1..S;~1 do Arr.E.X := {C} end %% go up for Y in E-1..S+1;~1 do Arr.Y.S := {C} end %% fill the inner rectangle if E - S > 1 then {Fill Arr S+1 E-1 C} end end
fun {Counter N} C = {NewCell N} in fun {$} C := @C + 1 end end
in
{Inspect {Spiral 5}}</lang>
Perl
<lang perl>sub spiral
{my ($n, $x, $y, $dx, $dy, @a) = (shift, 0, 0, 1, 0); foreach (0 .. $n**2 - 1) {$a[$y][$x] = $_; my ($nx, $ny) = ($x + $dx, $y + $dy); ($dx, $dy) = $dx == 1 && ($nx == $n || defined $a[$ny][$nx]) ? ( 0, 1) : $dy == 1 && ($ny == $n || defined $a[$ny][$nx]) ? (-1, 0) : $dx == -1 && ($nx < 0 || defined $a[$ny][$nx]) ? ( 0, -1) : $dy == -1 && ($ny < 0 || defined $a[$ny][$nx]) ? ( 1, 0) : ($dx, $dy); ($x, $y) = ($x + $dx, $y + $dy);} return @a;}
foreach (spiral 5)
{printf "%3d", $_ foreach @$_; print "\n";}</lang>
Perl 6
Object-oriented Solution
Suppose we set up a Turtle class like this: <lang perl6>enum Dir < north northeast east southeast south southwest west northwest >; my $debug = 0;
class Turtle {
has @.loc = 0,0; has Dir $.dir = north;
my @dv = [0,-1], [1,-1], [1,0], [1,1], [0,1], [-1,1], [-1,0], [-1,-1]; my @num-to-dir = Dir.invert.sort».value; my $points = +Dir;
my %world; my $maxegg; my $range-x; my $range-y;
method turn-left ($angle = 90) { $!dir -= $angle / 45; $!dir %= $points; } method turn-right($angle = 90) { $!dir += $angle / 45; $!dir %= $points; }
method lay-egg($egg) {
%world{~@!loc} = $egg; $maxegg max= $egg; $range-x minmax= @!loc[0]; $range-y minmax= @!loc[1];
}
method look($ahead = 1) {
my $there = @!loc »+« (@dv[$!dir] X* $ahead); say "looking @num-to-dir[$!dir] to $there" if $debug; %world{~$there};
}
method forward($ahead = 1) {
my $there = @!loc »+« (@dv[$!dir] X* $ahead); @!loc = @($there); say " moving @num-to-dir[$!dir] to @!loc[]" if $debug;
}
method showmap() {
my $form = "%{$maxegg.chars}s"; my $endx = $range-x.max;
for $range-y.list X $range-x.list -> $y, $x {
print (%world{"$x $y"} // ).fmt($form); print $x == $endx ?? "\n" !! ' '; }
}
}</lang> Now we can build the spiral in the normal way from outside-in like this: <lang perl6>sub MAIN($size as Int) {
my $t = Turtle.new(dir => east); my $counter = 0; $t.forward(-1); for 0..^ $size -> $ {
$t.forward; $t.lay-egg($counter++);
} for $size-1 ... 1 -> $run {
$t.turn-right; $t.forward, $t.lay-egg($counter++) for 0..^$run; $t.turn-right; $t.forward, $t.lay-egg($counter++) for 0..^$run;
} $t.showmap;
}</lang> Or we can build the spiral from inside-out like this: <lang perl6>sub MAIN($size as Int) {
my $t = Turtle.new(dir => ($size %% 2 ?? south !! north)); my $counter = $size * $size; while $counter {
$t.lay-egg(--$counter); $t.turn-left; $t.turn-right if $t.look; $t.forward;
} $t.showmap;
}</lang>
Note that with these "turtle graphics" we don't actually have to care about the coordinate system, since the showmap
method can show whatever rectangle was modified by the turtle. So unlike the standard inside-out algorithm, we don't have to find the center of the matrix first.
Procedural Solution
<lang perl6>sub spiral_matrix ( $n ) {
my @sm; my $len = $n; my $pos = 0;
for ^($n/2).ceiling -> $i { my $j = $i + 1; my $e = $n - $j;
@sm[$i ][$i + $_] = $pos++ for ^( $len); # Top @sm[$j + $_][$e ] = $pos++ for ^(--$len); # Right @sm[$e ][$i + $_] = $pos++ for reverse ^( $len); # Bottom @sm[$j + $_][$i ] = $pos++ for reverse ^(--$len); # Left }
return @sm;
}
say .fmt('%3d') for spiral_matrix(5);</lang>
Output:
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
PL/I
<lang PL/I>/* Generates a square matrix containing the integers from 0 to N**2-1, */ /* where N is the length of one side of the square. */ /* Written 22 February 2010. */
declare n fixed binary;
put skip list ('Please type the size of the square:'); get list (n);
begin;
declare A(n,n) fixed binary; declare (i, j, iinc, jinc, q) fixed binary;
A = -1;
i, j = 1; iinc = 0; jinc = 1; do q = 0 to n**2-1; if a(i,j) < 0 then a(i,j) = q; else do; /* back up */ j = j -jinc; i = i - iinc; /* change direction */ if iinc = 0 & jinc = 1 then do; iinc = 1; jinc = 0; end; else if iinc = 1 & jinc = 0 then do; iinc = 0; jinc = -1; end; else if iinc = 0 & jinc = -1 then do; iinc = -1; jinc = 0; end; else if iinc = -1 & jinc = 0 then do; iinc = 0; jinc = 1; end; /* Take one step in the new direction */ i = i + iinc; j = j + jinc; a(i,j) = q; end; if i+iinc > n | i+iinc < 1 then do; iinc = 0; jinc = 1; if j+1 > n then jinc = -1; else if j-1 < 1 then jinc = 1; if a(i+iinc,j+jinc) >= 0 then jinc = -jinc; /* j = j + jinc; /* to move on from the present (filled) position */ end; else i = i + iinc; if j+jinc > n | j+jinc < 1 then do; jinc = 0; iinc = 1; if i+1 > n then iinc = -1; else if i-1 < 1 then iinc = 1; if a(i+iinc,j+jinc) >= 0 then iinc = -iinc; i = i + iinc; /* to move on from the present (filled) position */ end; else j = j + jinc; end;
/* Display the square. */ do i = 1 to n; put skip edit (A(i,*)) (F(4)); end;
end;</lang>
PicoLisp
This example uses 'grid' from "lib/simul.l", which maintains a two-dimensional structure and is normally used for simulations and board games. <lang PicoLisp>(load "@lib/simul.l")
(de spiral (N)
(prog1 (grid N N) (let (Dir '(north east south west .) This 'a1) (for Val (* N N) (=: val Val) (setq This (or (with ((car Dir) This) (unless (: val) This) ) (with ((car (setq Dir (cdr Dir))) This) (unless (: val) This) ) ) ) ) ) ) )
(mapc
'((L) (for This L (prin (align 3 (: val)))) (prinl) ) (spiral 5) )</lang>
Output:
1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9
PureBasic
<lang PureBasic>Procedure spiralMatrix(size = 1)
Protected i, x = -1, y, count = size, n Dim a(size - 1,size - 1) For i = 1 To count x + 1 a(x,y) = n n + 1 Next Repeat count - 1 For i = 1 To count y + 1 a(x,y) = n n + 1 Next For i = 1 To count x - 1 a(x,y) = n n + 1 Next
count - 1 For i = 1 To count y - 1 a(x,y) = n n + 1 Next For i = 1 To count x + 1 a(x,y) = n n + 1 Next Until count < 1 PrintN("Spiral: " + Str(Size) + #CRLF$) Protected colWidth = Len(Str(size * size - 1)) + 1 For y = 0 To size - 1 For x = 0 To size - 1 Print("" + LSet(Str(a(x, y)), colWidth, " ") + "") Next PrintN("") Next PrintN("")
EndProcedure
If OpenConsole()
spiralMatrix(2) PrintN("") spiralMatrix(5) Print(#CRLF$ + #CRLF$ + "Press ENTER to exit") Input() CloseConsole()
EndIf</lang> Sample output:
Spiral: 2 0 1 3 2 Spiral: 5 0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
Python
<lang python>def spiral(n):
dx,dy = 1,0 # Starting increments x,y = 0,0 # Starting location myarray = [[None]* n for j in range(n)] for i in xrange(n**2): myarray[x][y] = i nx,ny = x+dx, y+dy if 0<=nx<n and 0<=ny<n and myarray[nx][ny] == None: x,y = nx,ny else: dx,dy = -dy,dx x,y = x+dx, y+dy return myarray
def printspiral(myarray):
n = range(len(myarray)) for y in n: for x in n: print "%2i" % myarray[x][y], print
printspiral(spiral(5))</lang> Sample output:
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
Recursive Solution
<lang python>def spiral(n):
def spiral_part(x, y, n): if x == -1 and y == 0: return -1 if y == (x+1) and x < (n // 2): return spiral_part(x-1, y-1, n-1) + 4*(n-y) if x < (n-y) and y <= x: return spiral_part(y-1, y, n) + (x-y) + 1 if x >= (n-y) and y <= x: return spiral_part(x, y-1, n) + 1 if x >= (n-y) and y > x: return spiral_part(x+1, y, n) + 1 if x < (n-y) and y > x: return spiral_part(x, y-1, n) - 1
array = [[0] * n for j in xrange(n)] for x in xrange(n): for y in xrange(n): array[x][y] = spiral_part(y, x, n) return array
for row in spiral(5):
print " ".join("%2s" % x for x in row)</lang>
Adding a cache for the spiral_part function it could be quite efficient.
Another way, based on preparing lists ahead <lang python>def spiral(n):
dat = [[None] * n for i in range(n)] le = [[i + 1, i + 1] for i in reversed(range(n))] le = sum(le, [])[1:] # for n = 5 le will be [5, 4, 4, 3, 3, 2, 2, 1, 1] dxdy = [[1, 0], [0, 1], [-1, 0], [0, -1]] * ((len(le) + 4) / 4) # long enough x, y, val = -1, 0, -1 for steps, (dx, dy) in zip(le, dxdy): x, y, val = x + dx, y + dy, val + 1 for j in range(steps): dat[y][x] = val if j != steps-1: x, y, val = x + dx, y + dy, val + 1 return dat
for row in spiral(5): # calc spiral and print it
print ' '.join('%3s' % x for x in row)</lang>
Functional Solution
<lang python>import itertools
concat = itertools.chain.from_iterable def partial_sums(items):
s = 0 for x in items: s += x yield s
grade = lambda xs: sorted(range(len(xs)), key=xs.__getitem__) values = lambda n: itertools.cycle([1,n,-1,-n]) counts = lambda n: concat([i,i-1] for i in range(n,0,-1)) reshape = lambda n, xs: zip(*([iter(xs)] * n))
spiral = lambda n: reshape(n, grade(list(partial_sums(concat(
[v]*c for c,v in zip(counts(n), values(n)))))))
for row in spiral(5):
print(' '.join('%3s' % x for x in row))</lang>
R
<lang R>runsum <- function(v) {
rs <- c() for(i in 1:length(v)) { rs <- c(rs, sum(v[1:i])) } rs
}
grade <- function(v) {
g <- vector("numeric", length(v)) for(i in 1:length(v)) { g[v[i]] <- i-1 } g
}
makespiral <- function(spirald) {
series <- vector("numeric", spirald^2) series[] <- 1 l <- spirald-1; p <- spirald+1 s <- 1 while(l > 0) { series[p:(p+l-1)] <- series[p:(p+l-1)] * spirald*s series[(p+l):(p+l*2-1)] <- -s*series[(p+l):(p+l*2-1)] p <- p + l*2 l <- l - 1; s <- -s } matrix(grade(runsum(series)), spirald, spirald, byrow=TRUE)
}
print(makespiral(5))</lang>
Recursive Solution
<lang R>#more general function, v is assumed to be a vector spiralv<-function(v){
n<-sqrt(length(v)) if(n!=floor(n)) stop(simpleError("length of v should be a square of an integer")) if(n==0) stop(simpleError("v should be of positive length")) if(n==1) M<-matrix(v,1,1) else M<-rbind(v[1:n],cbind(spiralv(v[(2*n):(n^2)])[(n-1):1,(n-1):1],v[(n+1):(2*n-1)])) M
}
- wrapper
spiral<-function(n){spiralv(0:(n^2-1))}
- check:
spiral(5)</lang>
REXX
Logic stolen (mostly) from the Fortran example. <lang rexx>/*REXX program to show a spiral in a square array (of any size). */
arg size . /*get the array size from arg. */ if size== then size=5 /*if no argument, use the default*/ tot=size**2 /*total # of elements in spiral. */ k=size /*K is the counter for the sprial*/ row=1 /*start with row one. */ col=0 /*start with col zero. */ n=0 /*start the sprial at 0 (zero).*/
/*─────────────────────────────────────build the spiral─────────────────*/
do n=0 for k; col=col+1; @.col.row=n; end do until n>=tot k=k-1 do n=n for k; row=row+1; @.col.row=n; end do n=n for k; col=col-1; @.col.row=n; end if n>=tot then leave k=k-1 do n=n for k; row=row-1; @.col.row=n; end do n=n for k; col=col+1; @.col.row=n; end end
/*─────────────────────────────────────display the spiral───────────────*/
do col=1 for size; _= do row=1 for size _=_ right(@.row.col,length(tot)) end say substr(_,2) end</lang>
Output (using the default array size of 5):
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
Output (using an array size of 36):
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 36 138 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 174 37 137 270 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 304 175 38 136 269 394 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 426 305 176 39 135 268 393 510 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 540 427 306 177 40 134 267 392 509 618 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 646 541 428 307 178 41 133 266 391 508 617 718 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 744 647 542 429 308 179 42 132 265 390 507 616 717 810 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 834 745 648 543 430 309 180 43 131 264 389 506 615 716 809 894 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 916 835 746 649 544 431 310 181 44 130 263 388 505 614 715 808 893 970 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 990 917 836 747 650 545 432 311 182 45 129 262 387 504 613 714 807 892 969 1038 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1056 991 918 837 748 651 546 433 312 183 46 128 261 386 503 612 713 806 891 968 1037 1098 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1114 1057 992 919 838 749 652 547 434 313 184 47 127 260 385 502 611 712 805 890 967 1036 1097 1150 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1164 1115 1058 993 920 839 750 653 548 435 314 185 48 126 259 384 501 610 711 804 889 966 1035 1096 1149 1194 1231 1232 1233 1234 1235 1236 1237 1238 1239 1206 1165 1116 1059 994 921 840 751 654 549 436 315 186 49 125 258 383 500 609 710 803 888 965 1034 1095 1148 1193 1230 1259 1260 1261 1262 1263 1264 1265 1240 1207 1166 1117 1060 995 922 841 752 655 550 437 316 187 50 124 257 382 499 608 709 802 887 964 1033 1094 1147 1192 1229 1258 1279 1280 1281 1282 1283 1266 1241 1208 1167 1118 1061 996 923 842 753 656 551 438 317 188 51 123 256 381 498 607 708 801 886 963 1032 1093 1146 1191 1228 1257 1278 1291 1292 1293 1284 1267 1242 1209 1168 1119 1062 997 924 843 754 657 552 439 318 189 52 122 255 380 497 606 707 800 885 962 1031 1092 1145 1190 1227 1256 1277 1290 1295 1294 1285 1268 1243 1210 1169 1120 1063 998 925 844 755 658 553 440 319 190 53 121 254 379 496 605 706 799 884 961 1030 1091 1144 1189 1226 1255 1276 1289 1288 1287 1286 1269 1244 1211 1170 1121 1064 999 926 845 756 659 554 441 320 191 54 120 253 378 495 604 705 798 883 960 1029 1090 1143 1188 1225 1254 1275 1274 1273 1272 1271 1270 1245 1212 1171 1122 1065 1000 927 846 757 660 555 442 321 192 55 119 252 377 494 603 704 797 882 959 1028 1089 1142 1187 1224 1253 1252 1251 1250 1249 1248 1247 1246 1213 1172 1123 1066 1001 928 847 758 661 556 443 322 193 56 118 251 376 493 602 703 796 881 958 1027 1088 1141 1186 1223 1222 1221 1220 1219 1218 1217 1216 1215 1214 1173 1124 1067 1002 929 848 759 662 557 444 323 194 57 117 250 375 492 601 702 795 880 957 1026 1087 1140 1185 1184 1183 1182 1181 1180 1179 1178 1177 1176 1175 1174 1125 1068 1003 930 849 760 663 558 445 324 195 58 116 249 374 491 600 701 794 879 956 1025 1086 1139 1138 1137 1136 1135 1134 1133 1132 1131 1130 1129 1128 1127 1126 1069 1004 931 850 761 664 559 446 325 196 59 115 248 373 490 599 700 793 878 955 1024 1085 1084 1083 1082 1081 1080 1079 1078 1077 1076 1075 1074 1073 1072 1071 1070 1005 932 851 762 665 560 447 326 197 60 114 247 372 489 598 699 792 877 954 1023 1022 1021 1020 1019 1018 1017 1016 1015 1014 1013 1012 1011 1010 1009 1008 1007 1006 933 852 763 666 561 448 327 198 61 113 246 371 488 597 698 791 876 953 952 951 950 949 948 947 946 945 944 943 942 941 940 939 938 937 936 935 934 853 764 667 562 449 328 199 62 112 245 370 487 596 697 790 875 874 873 872 871 870 869 868 867 866 865 864 863 862 861 860 859 858 857 856 855 854 765 668 563 450 329 200 63 111 244 369 486 595 696 789 788 787 786 785 784 783 782 781 780 779 778 777 776 775 774 773 772 771 770 769 768 767 766 669 564 451 330 201 64 110 243 368 485 594 695 694 693 692 691 690 689 688 687 686 685 684 683 682 681 680 679 678 677 676 675 674 673 672 671 670 565 452 331 202 65 109 242 367 484 593 592 591 590 589 588 587 586 585 584 583 582 581 580 579 578 577 576 575 574 573 572 571 570 569 568 567 566 453 332 203 66 108 241 366 483 482 481 480 479 478 477 476 475 474 473 472 471 470 469 468 467 466 465 464 463 462 461 460 459 458 457 456 455 454 333 204 67 107 240 365 364 363 362 361 360 359 358 357 356 355 354 353 352 351 350 349 348 347 346 345 344 343 342 341 340 339 338 337 336 335 334 205 68 106 239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 222 221 220 219 218 217 216 215 214 213 212 211 210 209 208 207 206 69 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70
Ruby
Using the print_matrix method from Reduced row echelon form#Ruby
<lang ruby>def spiral(n)
spiral = Array.new(n) {Array.new(n, nil)} # n x n array of nils runs = n.downto(0).each_cons(2).to_a.flatten # n==5; [5,4,4,3,3,2,2,1,1,0] delta = [[1,0], [0,1], [-1,0], [0,-1]].each x, y, value = -1, 0, -1 for run in runs dx,dy = begin delta.next rescue StopIteration delta.rewind retry end run.times do |i| x += dx y += dy value += 1 spiral[y][x] = value end end spiral
end
print_matrix spiral(5)</lang>
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
Scala
<lang scala>class Folder(){
var dir = (1,0) var pos = (-1,0) def apply(l:List[Int], a:Array[Array[Int]]) = { var (x,y) = pos //start position var (dx,dy) = dir //direction l.foreach {e => x = x + dx; y = y + dy; a(y)(x) = e } //copy l elements to array using current direction pos = (x,y) dir = (-dy, dx) //turn }
} def spiral(n:Int) = {
def dup(n:Int) = (1 to n).flatMap(i=>List(i,i)).toList val folds = n :: dup(n-1).reverse //define fold part lengths
var array = new Array[Array[Int]](n,n) val fold = new Folder()
var seq = (0 until n*n).toList //sequence to fold folds.foreach {len => fold(seq.take(len),array); seq = seq.drop(len)} array
}</lang> Explanation: if you see the sequence of numbers to spiral around as a tape to fold around, you can see this pattern on the lenght of tape segment to fold in each step:
Using this the solution becomes very simple,
- make the list of lengths to fold
- create the sequence to fold
- for each segment call a fold function that keeps track of where it is and knows how to turn around.
It's simple to make this generic, changing start position, initial direction, etc. The code could be more compact, but I'm leaving it like this for clarity.
Seed7
<lang seed7>$ include "seed7_05.s7i";
const type: matrix is array array integer;
const func matrix: spiral (in integer: n) is func
result var matrix: myArray is matrix.value; local var integer: i is 0; var integer: dx is 1; var integer: dy is 0; var integer: x is 1; var integer: y is 1; var integer: nx is 0; var integer: ny is 0; var integer: swap is 0; begin myArray := n times n times 0; for i range 1 to n**2 do myArray[x][y] := i; nx := x + dx; ny := y + dy; if nx >= 1 and nx <= n and ny >= 1 and ny <= n and myArray[nx][ny] = 0 then x := nx; y := ny; else swap := dx; dx := -dy; dy := swap; x +:= dx; y +:= dy; end if; end for; end func;
const proc: writeMatrix (in matrix: myArray) is func
local var integer: x is 0; var integer: y is 0; begin for key y range myArray do for key x range myArray[y] do write(myArray[x][y] lpad 4); end for; writeln; end for; end func;
const proc: main is func
begin writeMatrix(spiral(5)); end func;</lang>
Output:
1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9
Tcl
Using print_matrix
from Matrix Transpose#Tcl
<lang tcl>package require Tcl 8.5
namespace path {::tcl::mathop}
proc spiral size {
set m [lrepeat $size [lrepeat $size .]] set x 0; set dx 0 set y -1; set dy 1 set i -1 while {$i < $size ** 2 - 1} { if {$dy == 0} { incr x $dx if {0 <= $x && $x < $size && [lindex $m $x $y] eq "."} { lset m $x $y [incr i] } else { # back up and change direction incr x [- $dx] set dy [- $dx] set dx 0 } } else { incr y $dy if {0 <= $y && $y < $size && [lindex $m $x $y] eq "."} { lset m $x $y [incr i] } else { # back up and change direction incr y [- $dy] set dx $dy set dy 0 } } } return $m
}
print_matrix [spiral 5]</lang>
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
TSE SAL
<lang TSE SAL>
// library: math: create: array: spiral: inwards <description></description> <version control></version control> <version>1.0.0.0.15</version> (filenamemacro=creamasi.s) [<Program>] [<Research>] [kn, ri, mo, 31-12-2012 01:15:43] PROC PROCMathCreateArraySpiralInwards( INTEGER nI )
// e.g. PROC Main() // e.g. STRING s1[255] = "5" // e.g. IF ( NOT ( Ask( "math: create: array: spiral: inwards: nI = ", s1, _EDIT_HISTORY_ ) ) AND ( Length( s1 ) > 0 ) ) RETURN() ENDIF // e.g. PROCMathCreateArraySpiralInwards( Val( s1 ) ) // e.g. END // e.g. // e.g. <F12> Main() // INTEGER columnEndI = 0 // INTEGER columnBeginI = nI - 1 // INTEGER rowEndI = 0 // INTEGER rowBeginI = nI - 1 // INTEGER columnI = 0 // INTEGER rowI = 0 // INTEGER minI = 0 INTEGER maxI = nI * nI - 1 INTEGER I = 0 // INTEGER columnWidthI = Length( Str( nI * nI - 1 ) ) + 1 // INTEGER directionRightI = 0 INTEGER directionLeftI = 1 INTEGER directionDownI = 2 INTEGER directionUpI = 3 // INTEGER directionI = directionRightI // FOR I = minI TO maxI // // SetGlobalInt( Format( "MatrixS", columnI, ",", rowI ), I ) SetGlobalInt( Format( "MatrixS", columnI, ",", rowI ), I ) // // PutStrXY( ( Query( ScreenCols ) / 8 ) + columnI * columnWidthI, ( Query( ScreenRows ) / 8 ) + rowI, Str( I ), Color( BRIGHT RED ON WHITE ) ) PutStrXY( ( Query( ScreenCols ) / 8 ) + columnI * columnWidthI, ( Query( ScreenRows ) / 8 ) + rowI, Str( I + 1 ), Color( BRIGHT RED ON WHITE ) ) // CASE directionI // WHEN directionRightI // IF ( columnI < columnBeginI ) // columnI = columnI + 1 // ELSE // directionI = directionDownI // rowI = rowI + 1 // rowEndI = rowEndI + 1 // ENDIF // WHEN directionDownI // IF ( rowI < rowBeginI ) // rowI = rowI + 1 // ELSE // directionI = directionLeftI // columnI = columnI - 1 // columnBeginI = columnBeginI - 1 // ENDIF // WHEN directionLeftI // IF ( columnI > columnEndI ) // columnI = columnI - 1 // ELSE // directionI = directionUpI // rowI = rowI - 1 // rowBeginI = rowBeginI - 1 // ENDIF // WHEN directionUpI // IF ( rowI > rowEndI ) // rowI = rowI - 1 // ELSE // directionI = directionRightI // columnI = columnI + 1 // columnEndI = columnEndI + 1 // ENDIF // OTHERWISE // Warn( Format( "PROCMathCreateArraySpiralInwards(", " ", "case", " ", ":", " ", Str( directionI ), ": not known" ) ) // RETURN() // ENDCASE // ENDFOR //
END
PROC Main() STRING s1[255] = "5" IF ( NOT ( Ask( "math: create: array: spiral: inwards: nI = ", s1, _EDIT_HISTORY_ ) ) AND ( Length( s1 ) > 0 ) ) RETURN() ENDIF
PROCMathCreateArraySpiralInwards( Val( s1 ) )
END
</lang>
Ursala
Helpful hints from the J example are gratefully acknowledged. The spiral function works for any n, and results are shown for n equal to 5, 6, and 7. The results are represented as lists of lists rather than arrays. <lang Ursala>#import std
- import nat
- import int
spiral =
^H/block nleq-<lS&r+ -+
num@NiC+ sum:-0*yK33x+ (|\LL negation**)+ rlc ~&lh==1, ~&rNNXNXSPlrDlSPK32^lrtxiiNCCSLhiC5D/~& iota*+ iota+-
- cast %nLLL
examples = spiral* <5,6,7></lang> output:
< < <0,1,2,3,4>, <15,16,17,18,5>, <14,23,24,19,6>, <13,22,21,20,7>, <12,11,10,9,8>>, < <0,1,2,3,4,5>, <19,20,21,22,23,6>, <18,31,32,33,24,7>, <17,30,35,34,25,8>, <16,29,28,27,26,9>, <15,14,13,12,11,10>>, < <0,1,2,3,4,5,6>, <23,24,25,26,27,28,7>, <22,39,40,41,42,29,8>, <21,38,47,48,43,30,9>, <20,37,46,45,44,31,10>, <19,36,35,34,33,32,11>, <18,17,16,15,14,13,12>>>
Visual Basic
This requires VB6. <lang vb>Option Explicit
Sub Main()
print2dArray getSpiralArray(5)
End Sub
Function getSpiralArray(dimension As Integer) As Integer()
ReDim spiralArray(dimension - 1, dimension - 1) As Integer
Dim numConcentricSquares As Integer numConcentricSquares = dimension \ 2 If (dimension Mod 2) Then numConcentricSquares = numConcentricSquares + 1
Dim j As Integer, sideLen As Integer, currNum As Integer sideLen = dimension
Dim i As Integer For i = 0 To numConcentricSquares - 1 ' do top side For j = 0 To sideLen - 1 spiralArray(i, i + j) = currNum currNum = currNum + 1 Next
' do right side For j = 1 To sideLen - 1 spiralArray(i + j, dimension - 1 - i) = currNum currNum = currNum + 1 Next
' do bottom side For j = sideLen - 2 To 0 Step -1 spiralArray(dimension - 1 - i, i + j) = currNum currNum = currNum + 1 Next
' do left side For j = sideLen - 2 To 1 Step -1 spiralArray(i + j, i) = currNum currNum = currNum + 1 Next
sideLen = sideLen - 2 Next
getSpiralArray = spiralArray()
End Function
Sub print2dArray(arr() As Integer)
Dim row As Integer, col As Integer For row = 0 To UBound(arr, 1) For col = 0 To UBound(arr, 2) - 1 Debug.Print arr(row, col), Next Debug.Print arr(row, UBound(arr, 2)) Next
End Sub</lang>
VBA
Solution 1
<lang vb>Sub spiral()
Dim n As Integer, a As Integer, b As Integer Dim numCsquares As Integer, sideLen As Integer, currNum As Integer Dim j As Integer, i As Integer Dim j1 As Integer, j2 As Integer, j3 As Integer
n = 5
Dim spiralArr(9, 9) As Integer numCsquares = CInt(Application.WorksheetFunction.Ceiling(n / 2, 1)) sideLen = n currNum = 0 For i = 0 To numCsquares - 1 'do top side For j = 0 To sideLen - 1 currNum = currNum + 1 spiralArr(i, i + j) = currNum Next j
'do right side For j1 = 1 To sideLen - 1 currNum = currNum + 1 spiralArr(i + j1, n - 1 - i) = currNum Next j1
'do bottom side j2 = sideLen - 2 Do While j2 > -1 currNum = currNum + 1 spiralArr(n - 1 - i, i + j2) = currNum j2 = j2 - 1 Loop
'do left side j3 = sideLen - 2 Do While j3 > 0 currNum = currNum + 1 spiralArr(i + j3, i) = currNum j3 = j3 - 1 Loop
sideLen = sideLen - 2 Next i
For a = 0 To n - 1 For b = 0 To n - 1 Cells(a + 1, b + 1).Select ActiveCell.Value = spiralArr(a, b) Next b Next a
End Sub</lang>
Solution 2
<lang vb>Sub spiral(n As Integer)
Const FREE = -9 'negative number indicates unoccupied cell Dim A() As Integer Dim rowdelta(3) As Integer Dim coldelta(3) As Integer 'initialize A to a matrix with an extra "border" of occupied cells 'this avoids having to test if we've reached the edge of the matrix ReDim A(0 To n + 1, 0 To n + 1) 'Since A is initialized with zeros, setting A(1 to n,1 to n) to "FREE" 'leaves a "border" around it occupied with zeroes For i = 1 To n: For j = 1 To n: A(i, j) = FREE: Next: Next 'set amount to move in directions "right", "down", "left", "up" rowdelta(0) = 0: coldelta(0) = 1 rowdelta(1) = 1: coldelta(1) = 0 rowdelta(2) = 0: coldelta(2) = -1 rowdelta(3) = -1: coldelta(3) = 0 curnum = 0 'set current cell position col = 1 row = 1 'set current direction theDir = 0 'theDir = 1 will fill the matrix counterclockwise 'ok will be true as long as there is a free cell left ok = True Do While ok 'occupy current FREE cell and increase curnum A(row, col) = curnum curnum = curnum + 1
'check if next cell in current direction is free 'if not, try another direction in clockwise fashion 'if all directions lead to occupied cells then we are finished!
ok = False For i = 0 To 3 newdir = (theDir + i) Mod 4 If A(row + rowdelta(newdir), col + coldelta(newdir)) = FREE Then 'yes, move to it and change direction if necessary theDir = newdir row = row + rowdelta(theDir) col = col + coldelta(theDir) ok = True Exit For End If Next i Loop 'print result For i = 1 To n For j = 1 To n Debug.Print A(i, j), Next Debug.Print Next
End Sub</lang> Sample output:
spiral 5 0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8 spiral 6 0 1 2 3 4 5 19 20 21 22 23 6 18 31 32 33 24 7 17 30 35 34 25 8 16 29 28 27 26 9 15 14 13 12 11 10
XPL0
<lang XPL0>def N=5; int A(N,N); int I, J, X, Y, Steps, Dir; include c:\cxpl\codes; [Clear; I:= 0; X:= -1; Y:= 0; Steps:= N; Dir:= 0; repeat for J:= 1 to Steps do
[case Dir&3 of 0: X:= X+1; 1: Y:= Y+1; 2: X:= X-1; 3: Y:= Y-1 other []; A(X,Y):= I; Cursor(X*3,Y); IntOut(0,I); I:= I+1; ]; Dir:= Dir+1; if Dir&1 then Steps:= Steps-1;
until Steps = 0; Cursor(0,N); ]</lang>
Output:
0 1 2 3 4 15 16 17 18 5 14 23 24 19 6 13 22 21 20 7 12 11 10 9 8
- Programming Tasks
- Matrices
- Ada
- ALGOL 68
- AutoHotkey
- BBC BASIC
- C
- C++
- C sharp
- Clojure
- CoffeeScript
- Common Lisp
- D
- E
- Euphoria
- Fortran
- F Sharp
- GAP
- Go
- Groovy
- Haskell
- Icon
- Unicon
- J
- Java
- JavaScript
- Liberty BASIC
- Lua
- Mathematica
- MATLAB
- Maxima
- NetRexx
- OCaml
- Octave
- Opal
- Opal examples needing attention
- Examples needing attention
- OoRexx
- Oz
- Perl
- Perl 6
- PL/I
- PicoLisp
- PureBasic
- Python
- R
- REXX
- Ruby
- Scala
- Seed7
- Tcl
- TSE SAL
- Ursala
- Visual Basic
- VBA
- XPL0