🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉
Avatar of stellartux

stellartux's solution

to Spiral Matrix in the Julia Track

Published at Mar 18 2021 · 0 comments
Instructions
Test suite
Solution

Given the size, return a square matrix of numbers in spiral order.

The matrix should be filled with natural numbers, starting from 1 in the top-left corner, increasing in an inward, clockwise spiral order, like these examples:

Spiral matrix of size 3
1 2 3
8 9 4
7 6 5
Spiral matrix of size 4
 1  2  3 4
12 13 14 5
11 16 15 6
10  9  8 7

Source

Reddit r/dailyprogrammer challenge #320 [Easy] Spiral Ascension. https://www.reddit.com/r/dailyprogrammer/comments/6i60lr/20170619_challenge_320_easy_spiral_ascension/

Version compatibility

This exercise has been tested on Julia versions >=1.0.

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

runtests.jl

using Test

include("spiral-matrix.jl")


@testset "Different valid values" begin
    @testset "Empty spiral" begin
        @test spiral_matrix(0) == Matrix{Int}(undef,0,0)
    end
    @testset "Trivial spiral" begin
        @test spiral_matrix(1) == reshape([1],(1,1))
    end
    @testset "Spiral of size 2" begin
        @test spiral_matrix(2) == [1 2; 4 3]
    end
    @testset "Spiral of size 3" begin
        @test spiral_matrix(3) == [1 2 3; 8 9 4; 7 6 5]
    end
    @testset "Spiral of size 4" begin
        @test spiral_matrix(4) == [1 2 3 4; 12 13 14 5; 11 16 15 6; 10 9 8 7]
    end
    @testset "Spiral of size 5" begin
        @test spiral_matrix(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]
    end
end
function spiral_matrix(T::Type{<:Integer}, n::Integer)::Matrix{T}
    result = Matrix{T}(undef, n, n)
    fillmatrix!(result, Iterators.Stateful(Iterators.countfrom(oneunit(T))))
    result
end

spiral_matrix(n::Integer) = spiral_matrix(typeof(n), n)

function fillmatrix!(result::AbstractMatrix, iter::Iterators.Stateful)
    if iszero(size(result, 1))
        return
    end

    fix = firstindex(result, 1)
    fiy = firstindex(result, 2)
    lix = lastindex(result, 1)
    liy = lastindex(result, 2)

    for i in fix:lix
        result[fiy, i] = popfirst!(iter) 
    end

    for j in fiy+1:liy
        result[j, lix] = popfirst!(iter)
    end

    for i in lix-1:-1:fix
        result[liy, i] = popfirst!(iter)
    end

    for j in liy-1:-1:fiy+1
        result[j, fix] = popfirst!(iter)
    end

    fillmatrix!(view(result, fix+1:lix-1, fiy+1:liy-1), iter)
end

Community comments

Find this solution interesting? Ask the author a question to learn more.

stellartux's Reflection

Generic solution which can fill any AbstractMatrix with any Integer series.