14
\$\begingroup\$

3-Dimensional Minesweeper

I've been on a minesweeper kick for a while, but all the questions are for 2 dimensions (or that one in 1D). But 2D is 2 easy!

Challenge

Write the shortest code possible to fill in the clues for a 3-dimensional minesweeper grid, since extra clicks are not optimal.

Input

The board dimensions, taken in any order and reasonable format, and the mines as a list of 3-dimensional coordinates in any reasonable format and order.

Coordinates can be 0 or 1-indexed, but must be in the same order as the board dimensions.

Output

A 3-D list resembling a 2-D list of columns (consistent order) or a list of 2-D slices (in order, any perspective) to form the final 3-D board. The number of adjacent mines can either be a number 1-26 or the corresponding letter a-z (case insensitive, just be consistent), unless there are no adjacent mines and then it is 0. Mines can be any character/string that is not a number 0-26 or a letter a-z if those are used.

test cases

Board: 3x3x3
Mines: [[1,1,1]]
Output:
[[[1,1,1],
[1,1,1],
[1,1,1]],

[[1,1,1],
[1,*,1],
[1,1,1]],

[[1,1,1],
[1,1,1],
[1,1,1]]]
\$\endgroup\$
4
  • 1
    \$\begingroup\$ feel free to add test cases, I have finals this week and don't feel like formatting them :p \$\endgroup\$
    – pacman256
    Commented May 6 at 14:46
  • \$\begingroup\$ Must all mines be the same? \$\endgroup\$
    – Tbw
    Commented May 6 at 19:04
  • \$\begingroup\$ @tbw yes, it would be too confusing otherwise \$\endgroup\$
    – pacman256
    Commented May 6 at 22:19
  • \$\begingroup\$ can the downvoters please elaborate? \$\endgroup\$
    – pacman256
    Commented May 9 at 22:14

12 Answers 12

4
\$\begingroup\$

JavaScript (ES6), 147 bytes

-1 thanks to emanresu A

Expects (dim0, dim1, dim2, mines), where mines is a list of comma-separated strings.

Output format: integers for clues and Infinity for mines.

(p,q,r,a)=>(g=(s,c)=>[...Array(s).keys(n=0)].map(c))(r,z=>g(q,y=>g(p,x=>g(27,d=>a.map(v=>n+=v==[x+d%3-1,y+~-(d/3%3),z+~-(d/9%3)]&&1/(d!=13)))&&n)))

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ -1 if you take the mines as a list of comma-separated strings \$\endgroup\$
    – emanresu A
    Commented May 6 at 21:23
4
\$\begingroup\$

JavaScript (Node.js), 117 bytes

m=>s=>(g=(d,j=2,i=s[j])=>i--?[...g(d,j,i),g(m.map((v,k)=>~~d[k]+(v[j]-i)**2),j-1)]:i?[]:d.some(n=>(j-=n<4,!n))||~j)``

Try it online!

(mines: [number, number, number][]) => (size: [number, number, number]) => (number | true)[][][]
  • -2 bytes by l4m2
\$\endgroup\$
1
  • \$\begingroup\$ 119 \$\endgroup\$
    – l4m2
    Commented May 7 at 8:00
3
\$\begingroup\$

Charcoal, 34 bytes

EθEη⭆Eζ⟦ιλν⟧⎇№εν*§⁺0βLΦε⬤ν‹↔⁻ς§πσ²

Try it online! Link is to verbose version of code. Takes the dimensions as three arguments followed by the list of mines and uses 0a-z* for output. Explanation:

 θ                                  First dimension
E                                   Map over implicit range
   η                                Second dimension
  E                                 Map over implicit range
      ζ                             Third dimension
     E                              Map over implicit range
       ⟦ιλν⟧                        List of coordinates
    ⭆                               Map over list of lists
             №                      Count of
               ν                    Current coordinates in
              ε                     List of mines
            ⎇                       If found then
                *                   Literal string `*` else
                   0                Literal string `0`
                  ⁺                 Concatenated with
                    β               Predefined variable lowercase alphabet
                 §                  Indexed by
                       ε            List of mines
                      Φ             Filtered where
                         ν          Current coordinates
                        ⬤           All coordinates satisfy
                             ς      Current coordinate
                           ↔⁻       Absolute difference with
                               π    Current mine
                              §     Indexed by
                                σ   Innermost index
                          ‹         Is less than
                                 ²  Literal integer `2`
                     L              Take the length
                                    Implicitly print
\$\endgroup\$
3
\$\begingroup\$

MATLAB, 99 bytes

function M(s,m)
b=zeros(s);for n=m;b(n(1),n(2),n(3))=1;end;c=convn(b,ones(3,3,3),'same');c(b==1)=-1

Uses convn to do the convolution. Mines are marked with -1.

Test run

>> M( [3,5,3], ...
      [1,2; ...
       1,2; ...
       1,2 ] )
c(:,:,1) =
    -1     2     1     0     0
     2     2     1     0     0
     1     1     1     0     0
c(:,:,2) =
     2     2     1     0     0
     2    -1     1     0     0
     1     1     1     0     0
c(:,:,3) =
     1     1     1     0     0
     1     1     1     0     0
     1     1     1     0     0

Ungolfed, with comments describing parameters and results

function [markedGrid, clueGrid] = MinesweeperClues3D(sz, mineIndices)
    %MINESWEEPERCLUES3D make a 3D minesweeper grid

    % for https://codegolf.stackexchange.com/questions/272974/3-dimensional-minesweeper

    % param: sz (1,3) = size of game grid  
    % param: mineIndices (3,:) = positions of mines in columns 
    % result: clueGrid size(sz) = count of present and adjacent mines
    % result: markedGrid size(sz) = clueGrid with mines marked as negative

    % make mineGrid with mines marked as 1, else 0
    mineGrid = zeros(sz);
    for mineIndex = mineIndices
        % mark this mine position
        mineGrid(mineIndex(1), mineIndex(2), mineIndex(3)) = 1;
    end

    % 3D convolution with 3x3x3 array of ones, for clues
    clueGrid = convn(mineGrid, ones(3,3,3),'same');

    % negate mine positions. (Could just overwrite with -1 or whatever.)
    markedGrid = clueGrid;
    markedGrid( mineGrid==1 ) = -clueGrid( mineGrid==1);

end
\$\endgroup\$
2
\$\begingroup\$

Jelly, 19 bytes

ŒpạṀỊɗÐḟⱮŒṬ¬S⁹ŒṬN¤o

A dyadic Link that accepts the dimensions of the board on the left and the mine locations (1-indexed) on the right and yields the fully clued board with -1 representing mines.

Try it online!

How?

ŒpạṀỊɗÐḟⱮŒṬ¬S⁹ŒṬN¤o - Link: list of integers, D; list of lists of integers, M
Œp                  - Cartesian product {D, rangified} -> AllCoords
        Ɱ           - map across {M} with:
      Ðḟ            -   filter discard those of {AllCoords} for which:
     ɗ              -     last three links as a dyad - f(Coord, MineCoord):
  ạ                 -       {Coord} absolute difererence {MineCoord} (vectorises)
   Ṁ                -       maximum -> max orthogonal distance to mine
    Ị               -       insignificant? -> mine or neighbour?
         ŒṬ         - as boolean multidimensional arrays
           ¬        - logical NOT (vectorises)
            S       - sum -> Distances (except positive numbers at mines)
                 ¤  - nilad followed by link(s) as a nilad:
             ⁹      -   chain's right argument -> M
              ŒṬ    -   as a boolean multidimensional array
                N   -   negate (vectorises) -> Flags = -1 at mines, 0 elsewhere
                  o - {Flags} logical OR {Distances} (vectorises)
\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js), 116 bytes

a=>g=(w,x,y,z=0)=>w?[...--w?g(w,x,y,z):[],g(x,y,z,w)]:a.map(v=>w+=[1/0,1][0|Math.hypot(x-v[0],y-v[1],z-v[2])]||0)&&w

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Uiua 0.11.0, 2823 bytes SBCS

⍜⊡±‿¯:/+≡⬚0↻☇1¬⇡↯.3¤⊸∊⇡

Try on Uiua Pad!

\$\endgroup\$
2
\$\begingroup\$

Python 3, 189 bytes

lambda x,y,z,s,r=range:[[[[str([sum((i%x-m[0])**8+(i//x%y-m[1])**8+(i//x//y-m[2])**8<4for m in s)for i in r(x*y*z)][a+b*x+c*y*x]),'@'][[a,b,c]in s]for a in r(x)]for b in r(y)]for c in r(z)]

-2 thanks to corvus

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ 195 bytes: Put lambda x,y,z,s,r=range and put `f=` in the header (not counting towards the size). \$\endgroup\$
    – corvus_192
    Commented May 7 at 15:39
2
\$\begingroup\$

Python 3, 96 bytes

f=lambda m,a=0,*s:[f([y+m*(x!=i)for x,*y in m if-2<x-i<2],*s)for i in range(a)]or~-all(m)|len(m)

Try it online!

Resursive approach, works with any number of dimensions

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

J, 24 bytes

[:+/2>(>.&|/@:-"1/]#:i.)

Try it online!

  • ]#:i.) Create all possible coordinates for the dimensions
  • (>.&|/@:-"1/] Create a multi-dimension "table" of the max of the absolute element-wise differences between all the coordinates and all the bombs. Any time this max is 1 or less, a bomb is adjacent.
  • [:+/2> So just "sum the planes" where the number is less than 2. This will automatically return the answer in the right shape.
\$\endgroup\$
1
\$\begingroup\$

APL(Dyalog Unicode), 27 bytes SBCS

{¯1@⍵+⌿∘∊⍤⊢⌺(3⌿3)∨⌿⍵∘.≡⍳⍺}

A dfn takes dimension as its left argument and indices of mines as its right argument. It marks the mines with -1 in the output.

{¯1@⍵+⌿∘∊⍤⊢⌺(3⌿3)∨⌿⍵∘.≡⍳⍺}
                       ⍳⍺    coordinates of the grid
                 ∨⌿⍵∘.≡⍳⍺    bit map of the mindefield
     +⌿∘∊⍤⊢⌺(3⌿3)            3 by 3 by 3 adjacent count
 ¯1@⍵                        with the mines marked as -1

Try it on APLgolf!

Another simpler one that has the same length.

​{¯1@⍵{+⌿∊⍵}⌺3 3 3⊢1@⍵⊢⍺⍴0}
\$\endgroup\$
1
\$\begingroup\$

Scala 3, 312 bytes

A port of @AnrimO's Python answer in Scala.


Golfed version. Attempt This Online!

(x,y,z,s)=>(for(c<-0to z-1)yield{(for(b<-0to y-1)yield{(for(a<-0to x-1)yield{if(s.contains(List(a,b,c)))"@"else(for(i<-0to(x*y*z-1))yield{if(s.exists(m=>(math.pow((i%x-m(0)),8)+math.pow((i/x%y-m(1)),8)+math.pow((i/x/y-m(2)),8))<4))"1"else"0"}).mkString("").charAt(a+b*x+c*y*x).toString}).toList}).toList}).toList

Ungolfed version. Attempt This Online!

object Main {
  def f(x: Int, y: Int, z: Int, s: List[List[Int]]): List[List[List[String]]] = {
    def inRange(m: List[Int], i: Int): Boolean = {
      (math.pow((i % x - m(0)), 8) + math.pow((i / x % y - m(1)), 8) + math.pow((i / x / y - m(2)), 8)) < 4
    }

    val result = for (c <- 0 until z) yield {
      val layer = for (b <- 0 until y) yield {
        val row = for (a <- 0 until x) yield {
          val cell = for (i <- 0 until (x * y * z)) yield {
            val condition = s.exists(m => inRange(m, i))
            if (condition) "1" else "0"
          }
          var value = cell.mkString("").charAt(a + b * x + c * y * x).toString
          if (s.contains(List(a, b, c))) value = "@"
          value
        }
        row.toList
      }
      layer.toList
    }
    result.toList
  }

  def main(args: Array[String]): Unit = {
    val result = f(4, 3, 3, List(List(1, 1, 1)))
    println(result.map(_.map(_.mkString(" ")).mkString("\n")).mkString("\n\n"))
  }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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