2

this is a question about this codefight callenge.

The contestant is asked to check if a minesweeper field, represented as a 2D-Array is valid.

Details: Each cell of Minesweeper gameboard can be:

  • a mine (appears as 9)
  • or a number representing the number of mines in its surrounding cells (a cell is considered as surrounding another cell when this cell meets that cell on at least 1 corner) (appears as 0 - 8)

My approach (which works):

  • loop through all items
  • check neighbors for mines (and count number of mines, if there are any)
  • compare number of found mines with number on tile
  • return false, if numbers are unequal, else continue

Could someone please explain to me how this approach works?

minesweeper1 = g =>
!g.some((r,i) =>
      r.some((c,j) =>
            c < 9 && (f = d => d-- ? f(d) - ((g[i + ~-(d/3)] || 0)[j + d%3 - 1] > 8) : c)(9)
           )
     )

How much I understand:

  • g is the 2D-array, representing the field
  • .some will test, if an Element in the array will pass a test
  • r are the single single rows in the field
  • c is every single element in each row
  • What are i and j? Counters?
  • What is d?
  • what is the advantage of writing code so cryptic?
User12547645
  • 6,955
  • 3
  • 38
  • 69
  • 1
    The reason of writing code so cryptic can be only two - 1: Someone want the code not to be too clear for other people to see, or 2: It has been minified to save download size (which is pretty much useless for so little code, but could make sense if it is part of some larger codebase) - @all add other reasons if you know any! – Sventies Jul 27 '17 at 08:13
  • @Sventies You want to show off that you are still able to understand what is written there ;) I really don't get why people do that all the time. This might make the code super short, but I am not able to understand it anymore – User12547645 Jul 27 '17 at 08:21
  • 1
    not at all. It don't understand it completely, I wish I would, and if I did, I would give you a proper answer instead of a comment. Just thought I might help with giving a short answer to one of your questions - the last one. – Sventies Jul 27 '17 at 08:24
  • @Sventies Do you understand what the function f does and what the parameter d is? – User12547645 Jul 27 '17 at 08:32
  • Nope, sorry. Btw how did you get this answer? – Sventies Jul 27 '17 at 08:34
  • Go to the challenge https://codefights.com/challenge/ZXRv42mfhbiTTDrEB/solutions/6QrJxddLASiRxtFor and click "SOLUTIONS". This is a JS solution written by hieunt1980 – User12547645 Jul 27 '17 at 08:38
  • 1
    To answer your last point: google *code golf* and youll find people who love such code (including myself ;)), so the answer is probably: just for fun :0 – Jonas Wilms Jul 27 '17 at 08:58
  • 1
    @User12547645 Im pretty sure i and j are the indices (row and column number respectively), where r and c are the values itself. Variable d is declared in the lambda (anonymous function) "f", which is later used and passed value "9" I think. – Glubus Jul 27 '17 at 09:06

1 Answers1

4
minesweeper1 = mainarray => // an arrow function, that gets the two d array passed
!mainarray.some((row,rownumber) =>
  row.some((field,columnumber) =>//checking the 2d array if some of the fields
        field < 9 && (//is not a mine
          recursive = d => //and the magic recursive function is true
            d-- 
            ? recursive(d) /* get the value of one lower d*/ - ((mainarray[rownumber + ~-(d/3)] || 0)[columnnumber + d%3 - 1] > 8) /* subtract one if this magic is true */
             : field//if d=-1 it returns field
         )(9)//the starting point of the recursive function d=9
   ))

So it basically checks, if some of the fields is not a mine (field<9) and the recursive function successes. The recursive function goes from 0 to 9 and processes the followig steps:

field //the current value as start value

//d=0
- (mainarray[rownumber - Math.floor(d/3)-1][columnnumber + d%3 ] >8)
//d=1
 - (mainarray[rownumber - Math.floor(d/3)-1][columnnumber + d%3 ] >8)
//...
//repeat until d=9

( If youve wondered about the ~-(d/3) it does the following:

0-2: ~-([0,1,2]/3) = ~-0 = -(-0)-1 = -1
3-5: ~-([3,4,5]/3) = ~-1 = -(-1)-1 = 0
6-8: ~-([6,7,8]/3) = ~-2 = -(-2)-1 = 1

)

So basically the function will go through this pattern ( 0 is field , X is the currently checked position)

d=0
X - -
- 0 -
- - -

d=1
- X -
- 0 -
- - -

d=2
- - X
- 0 -
- - -

d=3
- - -
X 0 -
- - -

...

And then if theres a mine (>8) it substracts 1 (true) from field. So if the field is 4 and there are 4 mines around, it will do 4-1-1-1-1, so the whole thing is 0, which is falsy:

Two examples (field is the middle one):

9 9 9
9 4 1
1 1 0

So the recursive function will return 0 (falsy) ( 4-1-1-1-1)

9 9 9
2 4 1
0 0 0

This will return 1 (truthy) (4-1-1-1)

So this recursive function could be renamed to countaroundiswrong :

!mainarray.some((row,rownumber) =>
  row.some((field,columnumber) =>
    fieldismine() && countaroundiswrong(mainarray,field,rownumber,columnumber)
  )
)

So if theres a mine, and the count around is wrong, theres some field found and the whole thing is true, gets inverted and the result is false. A non cryptic way:

function countaroundiswrong(mainarray,field,col,row){
 for(var x=-1;x<2;x++){
  for(var y=-1;y<2;y++){
    if(mainarray[row+x] && mainarray[row+x][col+y]){
      if(mainarray[row+x][col+y] >8){
         field--;
      }
    }
   }
  }
  return field;
}
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151