填写扫雷线索


54

扫雷(Minesweeper)是一种流行的益智游戏,您必须在不单击这些图块的情况下发现哪些图块是“地雷”。每个图块要么是地雷(用表示*),要么是线索,即从0到8的数字表示在8个相邻图块中有多少是地雷。今天的任务是拿一个包含地雷的板子,并填写所有线索。例如,看下面的5x4板,有5个地雷:

 *  
*  * 
  *  
    *

填写线索后,董事会将如下所示:

2*211
*33*1
12*32
0112*

细节

您必须编写一个完整程序或一个函数,该函数接受仅包含空格和星号的字符网格,并输出另一个网格,其中每个空格都用相邻的地雷(星号)替换。这些是您的网格可接受的格式:

  • 带有换行符的字符串

  • 二维字符列表/单个字符串

  • 字符串列表

您可以假定网格至少为 1x1,尽管可能是所有地雷或所有空间。

输入网格将始终填充适当数量的空格。像往常一样,这是,因此存在标准漏洞,并且以字节为单位的最短答案为胜!

样品IO

为了看到空白,我将显示所有带有括号的示例IO。

Input:
[    * ]
[*     ]
[      ]
[      ]
[  **  ]
[ *  * ]

Output:
[1101*1]
[*10111]
[110000]
[012210]
[12**21]
[1*33*1]

Input:
[****]
[****]

Output:
[****]
[****]

Input:
[   ]
[   ]
[   ]
[   ]

Output:
[000]
[000]
[000]
[000]

Input:
[*   ]
[**  ]
[    ]
[   *]

Ouput:
[*310]
[**10]
[2221]
[001*]

Input:
[**    ]
[*    *]
[  *   ]
[      ]
[*     ]
[****  ]

Output:
[**1011]
[*4211*]
[12*111]
[121100]
[*43210]
[****10]

Input:
[     *    ]
[        * ]
[     *    ]
[**   ***  ]
[      *** ]
[          ]
[       ** ]
[  * *     ]
[*      ** ]
[       ** ]

Output:
[00001*1111]
[00002221*1]
[22102*4321]
[**102***31]
[221013***1]
[0000013542]
[0112111**1]
[12*2*12442]
[*212112**2]
[1100002**2]

2
仅供参考,我手工制作了所有示例IO,因此可能存在一些小错误。让我知道是否有什么问题,我会尽快修复。
DJMcMayhem


1
网格可以是非正方形的吗?
Ton Hospel '16

地雷可以用其他角色代表吗?
Akangka '16

@ChristianIrwan不,地雷永远是一个星号。
DJMcMayhem

Answers:


21

MATL18 17字节

感谢@ mbomb007对测试用例6的输入进行了更正

32>t3Y6Z+-6b(48+c

输入是2D char数组,格式为

[' *   '; '*  * '; '  *  '; '    *']

在线尝试!

测试用例:123456

说明

32>      % Input 2D char array implicitly. Transform it into a 2D logical
         % array with asterisk replaced by true and space by false
t        % Duplicate
3Y6      % Push [1 1 1; 1 0 1; 1 1 1]. This defines the neighbourhood
Z+       % 2D convolution, keeping size. Gives the number of neighbouring
         % mines for each position
-6       % Push -6
b        % Bubble up in stack
(        % Assign -6 to the entries indicated by the logical array, i.e.
         % to the positions that originally contained asterisks 
48+      % Add 48. This transforms each number of neighbouring mines
         % into its ASCII code, and -6 into 42 (ASCII code of asterisk)
c        % Convert to char. Display implicitly

1
哇。令人印象深刻。
BladorthinTheGrey

2
获得测试用例6会让我不喜欢玩实际的游戏。
魔术章鱼缸

为什么?测试用例6似乎是最现实的。
WBT

@carusocomputing获得测试用例2会使我大为恼火。:P
DJMcMayhem

10

JavaScript(ES6),114 96字节

a=>a.map((s,i)=>s.replace(/ /g,(_,j)=>g(k=>(s=a[i+k])?g(k=>s[j+k]>' '):0)),g=f=>f(-1)+f(0)+f(1))

编辑:由于@ETHproductions的想法,节省了18个字节。


我认为您可以通过定义一个函数来检查索引是否为非空间来节省一大堆:a=>a.map((s,i)=>s.replace(/ /g,(_,j)=>a.slice(i-!!i,i+2).reduce((t,s)=>t+(q=i=>s[i+j]>' ')(-1)+q(0)+q(1),0)))
ETHproductions'October 23'16

@ETHproductions我将您的想法发挥到了极致……我通常不会写函数参数!
尼尔

7

R,127112字节

function(M){a=nrow(M);for(i in seq(M))if(M[i]!="*")M[i]=sum(M[pmax(i+c(-1,1,-a+-1:1,a+-1:1),0)]=="*",na.rm=T);M}

感谢@gtwebb和@ sebastian-c的改进。

要点:

矩阵是R中的向量。您不需要2D索引即可取出元素。

seq(M)将返回与相同的“长度”(行x列)的序列M

您不能在R中混合使用正负提取索引。这M[-3]是合法的R代码,但不是所需要的。

输入采用R矩阵的形式。一些例子:

> M <- matrix("",5,5)
> M[3,3] <- "*"
> f(M)
     [,1] [,2] [,3] [,4] [,5]
[1,] "0"  "0"  "0"  "0"  "0" 
[2,] "0"  "1"  "1"  "1"  "0" 
[3,] "0"  "1"  "*"  "1"  "0" 
[4,] "0"  "1"  "1"  "1"  "0" 
[5,] "0"  "0"  "0"  "0"  "0" 
> M[2,2] <- "*"
> f(M)
     [,1] [,2] [,3] [,4] [,5]
[1,] "1"  "1"  "1"  "0"  "0" 
[2,] "1"  "*"  "2"  "1"  "0" 
[3,] "1"  "2"  "*"  "1"  "0" 
[4,] "0"  "1"  "1"  "1"  "0" 
[5,] "0"  "0"  "0"  "0"  "0" 
> M[3,2] <- "*"
> f(M)
     [,1] [,2] [,3] [,4] [,5]
[1,] "1"  "1"  "1"  "0"  "0" 
[2,] "2"  "*"  "3"  "1"  "0" 
[3,] "2"  "*"  "*"  "1"  "0" 
[4,] "1"  "2"  "2"  "1"  "0" 
[5,] "0"  "0"  "0"  "0"  "0" 
> 

1
您可以使用T代替来删除一些字符TRUE。我也设法从if函数之一中删除了一些括号:f=function(M){a=nrow(M);b=ncol(M);for(i in seq(M))if(M[i]!="*")M[i]=sum(M[pmax(i+c(-1,1,-a+-1:1,a+-1:1),0)]=="*",na.rm=T);M}
sebastian-c

1
您先定义b=ncol(M)然后不使用它,这样就可以摆脱它。
gtwebb

我可以删除四个字符(并进行矢量化处理):M->{a=nrow(M);p=M=='*';M[]=ifelse(p,'*',sapply(seq(M),i->sum(p[pmax(i+c(-1,1,-a+-1:1,a+-1:1),0)],na.rm=T)))}-但是,此作弊略有一点,因为它需要重新定义的<-lambda,请参阅klmr / functional / lambda
Konrad Rudolph

@Konrad有趣的主意,但我将其保留为基数R,谢谢!
JDL

6

Java,190字节

编辑:

  • -6个字节。感谢@Frozn
  • -1字节关闭。多亏我自己:)
  • -1字节关闭。还发现了一些错误。感谢@Kevin Cruijssen

ni

c->{for(int x,y,j,i=-1;++i<c.length;)for(j=-1;++j<c[0].length;){if(c[i][j]<33){c[i][j]=48;for(x=i-2;++x<i+2;)for(y=j-2;++y<j+2;)try{if(c[x][y]==43)c[i][j]++;}catch(Exception e){}}}return c;}

取消高尔夫:

public class Main{
  public static char[][] minesweeper(char[][] woclues){
    for(int i = 0; i < woclues.length ; i++){
      for(int j = 0; j < woclues[0].length ; j++){
        if( woclues[i][j] == ' '){
          woclues[i][j] = '0';
          for(int x = i - 1; x < i + 2 ; x++){
            for(int y = j - 1; y < j + 2 ; y++){
              try{
                if(woclues[x][y] == '*'){
                  woclues[i][j]++;
                }
              }catch( ArrayIndexOutOfBoundsException e){}
            }
          }
        }
      }
    }
    return woclues;
  }
  public static void main(String[]args){
    char[][] in = new char[args.length][args[0].length()];
    for(int i = 0; i < args.length;i++){
      in[i]=args[i].toCharArray();
    }
    for(char[] c:minesweeper(in)){
      System.out.println(new String(c));
    }
  }
}

Ideone。


您可以将char值与ASCII值进行比较,而ASCII值在大多数情况下应该较短。您也可以合并x,y,i,j
Frozn

我已经做了c[i][j]==32等等,只是改变了他们在Ungolfed部分
罗马格拉夫

我比Phyton矮。至少!
罗曼·格拉夫(RomanGräf)

您确定您未填写的代码正确吗?对于第一个测试用例,它输出:0000*1\n*10011\n110000\n000000\n00**10\n0*22*1。您能否添加ideone.com测试链接?编辑:另外,除非我自己做错了事,否则您的高尔夫球代码输出:ssss0s\n0sssss\nssssss\nssssss\nss00ss\ns0ss0s对于第一个测试用例(它已全部*替换为零。):S
Kevin Cruijssen

编辑。一旦我的互联网贫困,我将添加一个测试链接。
罗曼·格拉夫(RomanGräf),

5

JavaScript(ES6),107

输入/输出为字符串数组

f=l=>l.map((r,i)=>r.replace(/ /g,(c,j)=>(s=r=>(c+r).substr(j,3).split`*`.length,s(l[i-1])+s(l[i+1])+s(r)-3)))

请注意,当函数s被列表l的元素超出范围调用时,由于javascript的古怪转换规则,该参数aundefined并且c+a将导致" undefined"

更具可读性

l=>
  l.map(
    (r,i) =>
      r.replace(/ /g, (c,j) =>
        (
          s = a => (c+a).substr(j,3).split`*`.length,
          s(l[i-1])+s(l[i+1])+s(r)-3
        )
      )
  )

5

Python 2,138字节

def f(s):w=s.find('\n')+1;print''.join([c,`(s[i-(i>0):i+2]+(w*' '+s)[i-1:i+2]+s[i-1+w:i+2+w]).count('*')`][c==' ']for i,c in enumerate(s))

定义一个f接受输入字符串的函数,例如

"  *\n** \n*  \n"

并向STDOUT打印一个字符串:

23*
**2
*31

1
请从2(历数开始enumerate(s,2)),并更换所有出现i + 2ii - 1i - 3。这将节省几个字节。
罗伯托·邦瓦莱特

5

的JavaScript(ES6)186个 182 177 161 152字节

f=a=>{for(s='',y=a[0].length;y--;)for(s=`
`+s,x=a.length;x--;)(k=>{for(t=0,i=9;i--;)t+=(a[x+i%3-1]||[])[y+i/3-1|0]==k;s=(a[x][y]<k?t:k)+s})`*`;return s}

更新资料

上面的代码用于" *"return "2*"。在以下脚本中已修复此问题。

168个 167字节

f=a=>{for(s='',y=a[0].length;y--;)for(s=`
`+s,x=a.length;x--;)a[x][y]=='*'?s='*'+s:(k=>{for(t=0,j=3;j--;)for(i=3;i--;)t+=(a[x+i-1]||1)[y+j-1]=='*';s=t+s})`*`;return s}

在这里尝试。


1
我认为t+=(a[x+i%3-1]||[])[y+i/3-1|0]==k应该以类似的方式工作并为您节省try/ catch部分。
阿纳尔德

1
@Arnauld。实际上,读取文字数字的属性不会引发错误,因此也可以将其改进(a[x+i%3-1]||1)[y+i/3-1|0]
sbisit '16

4

Haskell,115个字节

z=zip[1..]
x%i=[a|(j,a)<-z x,abs(i-j)<2]
f x=[[head$[c|c>' ']++show(sum[1|'*'<-(%j)=<<x%i])|(j,c)<-z r]|(i,r)<-z x]

f在字符串列表上定义一个函数


3

Python 2,192个字节

-3个字节(多亏铜),如果允许修改输入网格,则为-10个字节,通过删除又增加了-11个continue字节,消除了计数器变量又增加了-12个字节

def f(L):
 n,S,s=len(L[0]),[0,1,2],[' '];P=[s*(n+2)];K=P+[s+x+s for x in L]+P
 for y in range(len(L)):
    for x in range(n):
     if'*'!=L[y][x]:L[y][x]=`sum(K[y+d][x+e]=='*'for d in S for e in S)`

使用字符列表,L并创建填充版本K,因此边界没有问题。缩进为

  1. 空间
  2. 标签
  3. Tab +空格
  4. Tab + Tab

用法:

s=""" *   
*  * 
  *  
    *"""
print s
s=[[c for c in x] for x in s.split('\n')]
f(s)
s='\n'.join([ ''.join(x) for x in s])
print s

1
少量打高尔夫球:您可以将前三个变量赋值放在用分号分隔的同一行上,并避免缩进。另外,用于if'*'==L[y][x]:保存字节。

如果分配r=range;在同一行n,S,s,则可以通过更换调用保存五个字符range(...)r(...)
alexwlchan '16

@alexwlchan这样做节省了2 *,ange所以8个字节,但是我必须加上,r,range它也是8个字节,所以一无所获。
Karl Napf

@KarlNapf Gah,您是对的-我忘记了range
alexwlchan '16

3

露比112

获取并返回一个字符串。字符串必须用换行符分隔并且换行符终止。

->s{w=1+s=~/\n/
s.size.times{|i|s[i]==' '&&(n=0;9.times{|j|(s+$/*w)[i+j%3-1+j/3*w-w]==?*&&n+=1};s[i])=n.to_s}
s}

在测试程序中

f=->s{
  w=(s=~/\n/)+1                              #Calculate width.
  s.size.times{|i|                           #For each char in s
    s[i]==' '&&(                             #If it is a space
      n=0                                    #set counter n to 0 and visit
      9.times{|j|                            #a 3x3 square of chars.
        (s+$/*w)[i+j%3-1+j/3*w-w]==?*&&n+=1  #If *, increment n.
      }                                      #(Pad s with w newlines to avoid *'s detected by wraparound.)
      s[i]=n.to_s                            #Write n back to s in string format
    )
  }
s}                                           #Return s.

puts f[
" *   
*  * 
  *  
    *
"]

3

TSQL 292 291个字节

打高尔夫球:

DECLARE @ varchar(max)=
' *   
*  * 
  *  
    *';
WITH C as(SELECT x+1i,substring(@,x+1,1)v,x/z r,x%z c FROM master..spt_values CROSS APPLY(SELECT number x,charindex(char(10),@)z)z WHERE type='P'and x<len(@))SELECT @=stuff(@,i,1,z)FROM(SELECT i,(SELECT count(*)FROM C WHERE abs(D.c-c)<2and abs(D.r-r)<2and'*'=v)z FROM C D WHERE''=v)h PRINT @

取消高尔夫:

DECLARE @ varchar(max)=
' *   
*  * 
  *  
    *';
WITH C as
(
  SELECT x+1i,substring(@,x+1,1)v,x/z r,x%z c
  FROM master..spt_values
  CROSS APPLY(SELECT number x,charindex(char(10),@)z)z
  WHERE type='P'and x<len(@)
)
SELECT @=stuff(@,i,1,z)
FROM
(
  SELECT
    i,
    (
      SELECT count(*)
      FROM C
      WHERE 
       abs(D.c-c)<2and abs(D.r-r)<2and'*'=v
    )z
  FROM C D
  WHERE''=v
)h
PRINT @

小提琴


请问;你的代码前面算?看来您已经数过了。
Erik the Outgolfer

@EriktheGolfer是的,在WITH之前有脚本。如果将其删除,编译器将给出错误。可以在小提琴中测试想法
t-clausen.dk

我的意思是,应该在通用源的字节数中吗?因为看起来它应该应该是“ Initial STDIN”语句的一部分。
暴民埃里克

@EriktheGolfer我真的不知道,我想它可以是声明的一部分。也可以排除 master ..如果脚本开头有USE master。但这却在小提琴中发出了令人讨厌的信息。
t-clausen.dk

我尝试将分号放在上一行,并且行得通。我认为最后一行很重要。
暴民埃里克(Erik the Outgolfer)'16年

2

拍框415字节

(let*((l(string->list s))(g (λ(r c)(if(or(>= r n)(>= c n)(< r 0)(< c 0))#f(list-ref l(+ c(* n r))))))(ng (λ(r c)(let*((h'(-1 0 1))(k(filter(λ(x)x)
(for*/list((i h)(j h)#:unless(= 0 i j))(g(+ r i)(+ c j))))))(count(λ(x)(equal? x #\*))k))))(k(for*/list((i n)(j n))(ng i j)))
(ol(map(λ(x y)(if(equal? x #\*)"*"(number->string y)))l k)))(for((i(* n n))(j ol))(display j)(when(= 0(modulo(add1 i)n))(displayln ""))))

取消高尔夫:

(define (f s n)
  (let* ((l (string->list s))
         (get                            ; fn to get value at a (row, col)
          (lambda(r c)                   ; #f if invalid row or col
            (if (or (>= r n)
                    (>= c n)
                    (< r 0)
                    (< c 0))
                #f (list-ref l (+ c (* n r))))))

         (neighbors                      ; fn to count neighboring "*"
          (lambda(r c)
            (let* ((h '(-1 0 1))
                   (u (filter
                       (lambda(x) x)
                       (for*/list ((i h)(j h)
                                   #:unless (= 0 i j))
                         (get (+ r i) (+ c j))))))
              (count (lambda(x)(equal? x #\*)) u))))

         (k (for*/list ((i n) (j n))    ; for each row,col count neighboring "*"
              (neighbors i j)))
         (ol(map (lambda(x y)           ; get outlist- replace blanks with neighboring star count
                   (if(equal? x #\*) 
                      "*"
                      (number->string y)))
                 l k)))

    (for ((i (* n n))(j ol))            ; display outlist
      (display j)
      (when (= 0 (modulo (add1 i) n))
        (displayln "")))))

测试(列表作为指定了列号的单个字符串;也可以使用空格):

(f "----*-*-------------------**---*--*-" 6) 

输出:

1101*1
*10111
110000
012210
12**21
1*33*1

2

PHP,145个 133 132 127字节

for($s=$argv[1];$s[$p];print$c)if(" "==$c=$s[$p++])for($y=-2;$y++<1;)for($x=$p-3;$x++<$p;)$c+="!"<$s[$x+$y*strpos($s,"\n")+$y];

将输入作为单个字符串,换行符分隔。用运行-r

分解

for($s=$argv[1];$s[$p]; // loop through all characters (including newlines)
    print$c                     // 3. print result
)
    if(" "==$c=$s[$p++])        // 1. if character is space
        for($y=-2;$y++<1;)      // 2. count surrounding asterisk characters
            for($x=$p-3;$x++<$p;)
                $c+="!"<$s[$x+$y*strpos($s,"\n")+$y];

"!">$n=$s[$p]而不是" "==$n=$s[$p]节省了一个字节
约尔格Hülsermann

@JörgHülsermann那会破坏换行符。
泰特斯

@JörgHülsermann...但该技巧适用于星号比较(在新版本中)
Titus

2

Turtlèd,99个字节

(我总是忘了链接:|)

用每行的括号括起来的输入

Turtlèd无法接受多行输入,因此在最后一行之后,写入|输入的信号末尾

请注意,不匹配的括号是因为括号括起来,将下一个字符解析为括号命令的一部分

[|!.([[]r+.][[l]d)][ u]d[|[]r( #012345678#l(*+)u(*+)r(*+)r(*+)d(*+)d(*+)l(*+)l(*+)ur.)]' [[l]' d]' 

在线尝试!

工作原理(一般说明):

|输入之前,它会在每行上写出输入内容,并带有方括号以帮助其识别每行的结尾。发生这种情况后,它会回到输入的顶部。它遍历输入中的每个字符。如果是一个空间,它将在空间周围四处寻找,为发现的每枚炸弹增加一个。每行之后,它将删除方括号。当到达最后一行时,使用| 在其中,它停止并删除|。网格是隐式打印的。


0

C,152个 150 147 145字节

i,j,r,c;f(B,R,C)char**B;{for(i=R*C;i--;)for(j=9;j--;){char*b=B[i/C]+i%C;r=i/C+j/3-1;c=i%C+j%3-1;r<0|c<0|r/R|c/C|*b&8||(*b=16|*b+(B[r][c]==42));}}

输入采用二维字符数组的形式,然后是行数和列数。结果将就地返回。

(大多数)不带高尔夫:

i, j, r, c;
f(B, R, C) char **B; {
    for (i = R*C; i--;)
        for (j = 9; j--;) {
            char *b = B[i/C] + i%C;
            r = i/C + j/3 - 1;
            c = i%C + j%3 - 1;
            r < 0 | c < 0 | r / R | c / C | *b & 8 ||
                (*b = 16 | *b + (B[r][c] == 42));
        }
}

这种方法很简单-遍历每个位置,遍历所有位置,并加所有星号。有两个位级别的技巧:

  • 当我们确定一个单元格是否为星号时,我们只需检查是否设置了八位位,因为该单元格中的数字必须小于8(最大单元格值)。

  • 我们可以通过OR-ing 16将空格字符转换为零字符。

编辑:通过/代替来打掉两个字节>=

编辑:通过反转循环的方向再增加五个字节。


0

C#,341字节

可以缩短的天真的实现。

s=>s=="*"?1:0;s=>{for(int i=0,j,n,l=s.Length,c=s[i].Length;i<l;++i)for(j=0;j<c;++j)if(s[i][j]!="*"){n=0;if(i>0){n+=a(s[i-1][j]);n+=j>0?a(s[i-1][j-1]):0;n+=j+1<c?a(s[i-1][j+1]):0;}n+=a(s[i][j]);n+=j>0?a(s[i][j-1]):0;n+=j+1<c?a(s[i][j+1]):0;if(i+1<l){n+=a(s[i+1][j]);n+=j>0?a(s[i+1][j-1]):0;n+=j+1<c?a(s[i+1][j+1]):0;}s[i][j]=n+"";}return s;};

0

Python 2,183字节

def s(m):
 j=m.find('\n')+1;q='q'*j*2;m=list(q+m+q)
 for i in range(len(m)):
  if m[i]==' ':m[i]=`sum([m[k+i]=='*'for k in [-j-1,-j,-j+1,-1,1,j-1,j,j+1]])`
 return''.join(m)[j*2:-j*2]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.