Black Hole challenge from codewars

7

2

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

s326280

Posted 2019-03-09T13:53:42.043

Reputation: 173

1Welcome 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 [tag:code-golf]. – Post Rock Garf Hunter – 2019-03-09T14:17:50.860

@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' – s326280 – 2019-03-09T14:59:37.580

If you want an easy winning criterion, the majority of the questions on this site are tagged as [tag:code-golf], meaning that the winning criterion is the least bytes. – senox13 – 2019-03-09T15:48:22.773

@senox, Yes. Thanks for helping me. I would go with least bytes as winning criterion – s326280 – 2019-03-09T15:50:04.140

May we instead take 1-indexed indices [a,b] (i.e. top-left is 1st row, 1st column, so [1,1] ...and your example 13 would be at [2,2])? – Jonathan Allan – 2019-03-09T19:11:01.797

Please ping me when you've addressed @JonathanAllan's question and I'll cast my vote to reopen. Welcome to PPCG, by the way :) Nice first challenge. For future reference, we have a Sandbox where you can post challenges for community feedback and iron out any issues before posting them to Main.

– Shaggy – 2019-03-09T20:48:12.577

6Does codewars allow their challenges to be posted on other sites? – Jo King – 2019-03-10T00:38:39.877

@JoKing. Am sorry, I dont know. – s326280 – 2019-03-10T14:06:31.687

@JonathanAllan Sounds good. – s326280 – 2019-03-10T14:07:06.153

Thanks, I made an update - it's best to edit the post accordingly rather than leaving specifications in the comment section - please check you agree with it. – Jonathan Allan – 2019-03-10T15:26:57.707

@JonathanAllan. Now I agree with 1-indexed array. So do I need to edit the (a,b) values ?. Since it is 1-indexed array, [a,b] starts from [1,1]. – s326280 – 2019-03-10T15:51:22.613

I edited to allow other indexing, but kept zero-indexing and row-major (top-bottom; left-right) as the default (hence why I added the sentence above the test cases too) if you click "edited ... mins ago" you can see the diff. – Jonathan Allan – 2019-03-10T16:05:01.227

4If you're going to accept an answer at all, then at least accept the one that is actually winning by the winning criterion – Jo King – 2019-03-14T08:48:18.827

Answers

10

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

TFeld

Posted 2019-03-09T13:53:42.043

Reputation: 19 246

it's interesting, the question seems to imply the input is always an even number, but your algorithm works for odd as well? – don bright – 2019-03-14T02:53:57.413

1@donbright The testcases have both even and odd numbers? – TFeld – 2019-03-14T07:33:31.980

lol oops! my bad – don bright – 2019-03-14T23:25:19.970

2

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)

Kevin Cruijssen

Posted 2019-03-09T13:53:42.043

Reputation: 67 575

1<αRIRì can be <αìR and 4L can be ā. – Emigna – 2019-03-14T07:31:48.580

@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.. – Kevin Cruijssen – 2019-03-14T07:47:46.280

1

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.

Nick Kennedy

Posted 2019-03-09T13:53:42.043

Reputation: 11 829

1

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!

Arnauld

Posted 2019-03-09T13:53:42.043

Reputation: 111 334

1

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

Jonathan Allan

Posted 2019-03-09T13:53:42.043

Reputation: 67 804

0

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

don bright

Posted 2019-03-09T13:53:42.043

Reputation: 1 189