7
\$\begingroup\$

I came across this challenge from codewars. I wish to know how to solve this problem. The problem description is given below.

Its elements are in range[1..n^2]. The matrix is filled by rings, from the outwards the innermost. Each ring is filled with numbers in the following way:

  1. The first number is written in the top left corner;
  2. The second number is written in the top right corner;
  3. The third number is written in the bottom right corner;
  4. The fourth number is written in the bottom left corner;
  5. Each next number is written next to the number written 4 steps before it, until the ring is filled.

The matrix is constructed when all numbers are written.``` Given the size of the hole, return the number written at (a, b) - you may use any consistent indexing, but please specify if (a, b) is anything other than 0-indexed and row-major.

Example

For n = 4, a = 1, b = 1, the output should be 13.

The hole looks like this:

[ [  1,  5,  9,  2 ] 
  [ 12, 13, 14,  6 ] 
  [  8, 16, 15, 10 ] 
  [  4, 11,  7,  3 ] 
] 

The element at (1, 1) is 13

Test cases

(a, b) is 0-indexed and row-major here.

n   a   b   result
1   0   0    1
2   0   0    1
3   0   0    1
4   0   0    1
2   0   1    2
3   0   1    5
3   1   1    9
4   1   1   13
4   2   1   16
5   2   3   22
\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to the site. As it stands your question is lacking a crucial component that we require of all questions, an "objective winning criterion". That is, an objective way to score answers. The most common one is code-golf. \$\endgroup\$ – Sriotchilism O'Zaic Mar 9 at 14:17
  • \$\begingroup\$ @SriotchilismO'Zaic, Hi When I heard about Programming Puzzles and Code gulf, I thought it's about asking a programming challenge and getting a solution to it. Am sorry, am new to this site. I don't know 'Objective winning criterion' \$\endgroup\$ – s326280 Mar 9 at 14:59
  • \$\begingroup\$ If you want an easy winning criterion, the majority of the questions on this site are tagged as code-golf, meaning that the winning criterion is the least bytes. \$\endgroup\$ – senox13 Mar 9 at 15:48
  • 6
    \$\begingroup\$ Does codewars allow their challenges to be posted on other sites? \$\endgroup\$ – Jo King Mar 10 at 0:38
  • 4
    \$\begingroup\$ If you're going to accept an answer at all, then at least accept the one that is actually winning by the winning criterion \$\endgroup\$ – Jo King Mar 14 at 8:48
10
\$\begingroup\$

Python 2, 120 119 90 bytes

def f(n,a,b):n-=1;A,B,C=min((a,b,1),(n-b,a,2),(n-a,n-b,3),(b,n-a,4));return(n-A)*4*A+4*B+C

Try it online!


Python 3, 87 bytes

def f(n,a,b):A,B=min((a,b+1/4),(n+~b,a+.5),(n+~a,n-b-1/4),(b,n-a));return(n+~A)*4*A+B*4

Try it online!

Returns a float

-3 bytes, thanks to Arnauld


Explanation:

This takes advantage of the fact that there is some symmetry to the matrix.

The matrix can be split into four quarters, which are equal when rotated (+ an offset of 1-3).

enter image description here

The first part A,B,C=... finds out which quarter the current coordinates are in, by finding the smallest coordinates, relative to each quarter:

enter image description here

(green: (a,b), yellow: (n-b,a), red: (n-a,n-b), blue: (b,n-a))

The coordinate pair is then converted to a value:

(0,0) = 1, (0,1) = 5, and so on; each coordinate is 4 larger than the previous.

sum((n-(i*2))*4for i in range(A)) skips the rows above, +(B-A)*4 moves along the row, and +C adds the offset.

sum((n-(i*2))*4for i in range(A))+(B-A)*4+C is shortened to (n-A)*4*A+4*B+C

\$\endgroup\$
  • \$\begingroup\$ it's interesting, the question seems to imply the input is always an even number, but your algorithm works for odd as well? \$\endgroup\$ – don bright Mar 14 at 2:53
  • 1
    \$\begingroup\$ @donbright The testcases have both even and odd numbers? \$\endgroup\$ – TFeld Mar 14 at 7:33
  • \$\begingroup\$ lol oops! my bad \$\endgroup\$ – don bright Mar 14 at 23:25
2
\$\begingroup\$

05AB1E (legacy), 36 31 28 25 bytes

<αìRDÀsā)ø{н`Š4*ŠD¹<α4**O

Port of @TFeld's Python answer, so make sure to upvote him!
-3 bytes thanks to @Emigna.

Inputs are \$n\$ and \$[a,b]\$.

Uses the legacy version instead of the new 05AB1E version, because there seems to be a bug with the sorting ({) of multidimensional lists.

Try it online or verify all test cases.

Explanation:

<          # Decrease the (implicit) input `n` by 1
 α         # Take the absolute difference with the (implicit) input-list
           #  (we now have `[n-1-a, n-1-b]`)
  ì        # Prepend the input (we now have `[n-1-a, n-1-b, a, b]`)
   R       # Reverse the list (we now have `[b, a, n-1-b, n-1-a]`)
DÀ         # Duplicate this list, and rotate it once towards the left
    s      # Swap these two lists
ā          # Push a list in the range [1, length_list] without popping the list: [1,2,3,4]
     )     # Wrap all three lists into a list (we now have 
           #  `[[a, n-1-b, n-1-a, b], [b, a, n-1-b, n-1-a], [1, 2, 3, 4]]`)
      ø    # Zip/transpose; swapping rows/columns (we now have
           #  `[[a, b, 1], [n-1-b, a, 2], [n-1-a, n-1-b, 3], [b, n-1-a, 4]]`)
       {н  # Get the minimum by sorting the lists and getting the first inner list
           # (since the minimum builtins in 05AB1E flatten multidimensional lists
           #  and give a single integer)
`          # Push all three values to the stack: `A`, `B`, and `C`
Š          # Triple-swap once, so the order is now `C`, `A`, `B`
 4*        # Multiply `B` by 4
Š          # Triple-swap again to `B*4`, `C`, `A`
 D         # Duplicate `A`
  ¹<α      # Take the absolute difference with `n-1` (so basically `n-1-A`)
     4*    # Multiply that by 4
       *   # Multiply it with the duplicated `A`
O          # Sum all values on the stack (`B*4 + C + (n-1-A)*4*A`)
           # (and output the result implicitly)
\$\endgroup\$
  • 1
    \$\begingroup\$ <αRIRì can be <αìR and 4L can be ā. \$\endgroup\$ – Emigna Mar 14 at 7:31
  • \$\begingroup\$ @Emigna I'm an idiot.. I tried some things with append, prepend, and rotates, and eventually ended up with what I had. Two reverses and a prepend.. Why not just prepend first and then reverse.. dohh.. Thanks! Oh, also thanks for ā. I always forget about that builtin for some reason.. \$\endgroup\$ – Kevin Cruijssen Mar 14 at 7:47
1
\$\begingroup\$

Jelly, 28 bytes

³_1ị’;1×4
’0;_ⱮpƝẎAµżJṂFµæ.Ç

Try it online!

Based on @TFeld’s python answer so be sure to upvote that one too.

\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 86 bytes

(w,y,x)=>[x+(Y=w+~y)*y,y+(w+=~x)*x,w+Y*y,Y+w*x][k=x<y?x>Y?2:3:x<Y?0:x>y?1:Y-y&&2]*4-~k

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Jelly, 20 bytes

ZUẎTḢṬ_Ʋṁ
+þ`ṠÇƬSœị@

A dyadic Link accepting n on the left and [a,b] (1-indexed) on the right.

Try it online!

How?

ZUẎTḢṬ_Ʋṁ - Link 1, next matrix (rotated): current matrix
Z         - transpose          }
 U        - reverse each row   } -> rotate clockwise 1/4
  Ẏ       - tighten into a flat list of values
       Ʋ  - last four links as a monad:
   T      -   truthy indices -- e.g. [0,0,1,0,1,1,0] -> [3,5,6]
    Ḣ     -   head (empty list yields 0)             ->  3
     Ṭ    -   un-truth (0 yields an empty list)      -> [0,0,1]
      _   - subtract (vectorises)                    -> [0,0,0,0,1,1,0]
        ṁ - mould to shape of the current matrix again

+þ`ṠÇƬSœị@ - Main Link: integer, n; list of integers [a,b]
  `         - using left (n) as both arguments:
 þ          -   table of (implicit range of integer arguments)
+           -     addition
   Ṡ        - sign -- now we have an n by n matrix of ones
     Ƭ      - collect up (a list of matrices) while results are different with:
    Ç       -   last Link (1) as a monad
      ¬     - logical NOT (replace the 1s with 0s and vice-versa)
       S    - sum (vectorises)
          @ - with swapped arguments:
        œị  -   multidimensional index into
\$\endgroup\$
0
\$\begingroup\$

Rust - 340 bytes

fn f(n:usize,x:usize,y:usize)->usize{let (mut r,d)=(0,(n-1)&1);for l in ((1+d)..=n).step_by(2) {let (mut i,m,mx,mut z)=(0,l/2,n/2,0);loop {z=4*i+n*n-l*l;let u=[mx+m-i-d,mx-m,mx+m-d,mx-m+i];if (x,y)==(u[0],u[1]){r=z+4}if (x,y)==(u[2],u[0]){r=z+3}if (x,y)==(u[3],u[2]){r=z+2}if (x,y)==(u[1],u[3]){r=z+1}i+=1;if i>=l-1{break};}}r}

still got some work to do, but it basically draws the whole spiral, centered on a point in the middle, and saves the value at requested point x,y.

ungolf spiral draw at play.rust-lang.org

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.