Заполните подсказки тральщика

54

Сапер - популярная игра-головоломка, в которой вы должны выяснить, какие плитки являются «минами», не нажимая на эти плитки. Каждая ячейка является либо шахтой (представленной *), либо подсказкой, то есть числом от 0 до 8, представляющим, сколько из 8 соседних плиток является минами. Ваша задача сегодня - взять доску с минами и заполнить все подсказки. Например, посмотрите на следующую доску 5х4 с 5 минами:

 *  
*  * 
  *  
    *

После заполнения подсказок доска будет выглядеть так:

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

подробности

Вы должны написать либо полную программу, либо функцию, которая принимает сетку символов, содержащую только пробелы и звездочки, и выводит другую сетку, где каждый пробел заменяется количеством смежных мин (звездочек). Любой из этих форматов является приемлемым для ваших сеток:

  • Строка с переводом строки

  • 2D список символов / односимвольные строки

  • Список строк

Вы можете предположить, что сетка будет по крайней мере 1x1, хотя возможно, что это будут все мины или все пространства.

Сетка ввода всегда будет заполнена соответствующим количеством пробелов. Как обычно, это , поэтому применяются стандартные лазейки и выигрывает самый короткий ответ в байтах!

Образец ввода-вывода

Чтобы вы могли видеть пробелы, я покажу все примеры ввода-вывода с квадратными скобками.

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]
DJMcMayhem
источник
2
К вашему сведению, я сделал весь пример ввода-вывода вручную, так что, возможно, там есть небольшие ошибки. Дайте мне знать, если что-то не так, и я постараюсь исправить это как можно скорее.
DJMcMayhem
1
Может ли сетка быть не квадратной?
Тон Хоспел
Может мины представлены другим персонажем?
Akangka
@ChristianIrwan Нет, мины всегда будут звездочкой.
DJMcMayhem

Ответы:

21

MATL , 18 17 байт

Спасибо @ mbomb007 за исправление на входе теста 6

32>t3Y6Z+-6b(48+c

Ввод представляет собой двумерный массив символов в формате

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

Попробуйте онлайн!

Контрольные примеры: 1 , 2 , 3 , 4 , 5 , 6 .

объяснение

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
Ух ты. Это впечатляет.
a25bedc5-3d09-41b8-82fb-ea6c353d75ae
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))

Редактировать: Сохранено 18 байт благодаря идее @ETHproductions.

Нил
источник
Я думаю, что вы можете сохранить связку, определив функцию для проверки, если индекс не является пробелом: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
@ETHproductions Я довел вашу идею до крайности ... Обычно я не пишу параметры функций!
Нил
7

R, 127 112 байт

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. Вам не нужно двумерное индексирование, чтобы получить элементы.

seq(M)вернет последовательность той же "длины" (строки х столбцы), что и 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" 
> 
JDL
источник
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)))}- однако, это немного обманывает, потому что требуется переопределенная <-лямбда, см. Klmr / functions / lambda
Конрад Рудольф
@ Конрад интересная идея, но я оставлю ее на базе R, спасибо!
JDL
6

Java, 190 байт

Редактировать:

  • -6 байтов. Благодаря @Frozn
  • -1 байт выключен. Спасибо себе :)
  • -1 байт выключен. Также заметили некоторые ошибки. Спасибо @Kevin Cruijssen

Snipet

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;}

Ungolfed:

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));
    }
  }
}

Идео это.

Роман Греф
источник
Вы можете сравнить значения char со значениями ASCII, которые в большинстве случаев должны быть короче. Вы также можете объединить декларацииx,y,i,j
Frozn
Я уже сделал c[i][j]==32и так далее, и просто изменил их в части Ungolfed
Роман Gräf
И я ниже, чем Фитон. По крайней мере!
Роман Греф,
Ты уверен, что твой негольфированный код правильный? Для первого теста он выводит: 0000*1\n*10011\n110000\n000000\n00**10\n0*22*1. Не могли бы вы добавить тестовую ссылку на ideone.com? РЕДАКТИРОВАТЬ: Кроме того, если я не делаю что-то не так, ваш вывод кода в гольф: ssss0s\n0sssss\nssssss\nssssss\nss00ss\ns0ss0sдля первого теста (он заменил все *на нули ..): S
Кевин Круйссен
Ред. Я добавлю тестовую ссылку, как только мой интернет-магазин позволит мне это сделать.
Роман Греф
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 вне границ, параметр aимеет undefinedи c+aбудет результатом " undefined"благодаря необычным правилам преобразования javascript

Более читаемый

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
        )
      )
  )
edc65
источник
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 + 2с iи i - 1с i - 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}

Обновить

Код выше для " *"возврата "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}

Попробуй это здесь.

sbisit
источник
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].
сбисить
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 байта благодаря Copper, -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
@alexwlchan делает это экономит 2 * angeоколо того 8 байт, но я должен добавить ,rи ,rangeкоторый также 8 байт , поэтому ничего не заработал.
Карл Напф
@KarlNapf Гах, ты прав - я забыл об этом range.
alexwlchan
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[
" *   
*  * 
  *  
    *
"]
Уровень реки St
источник
3

TSQL 292 291 байт

Golfed:

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 @

Ungolfed:

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 @

скрипка

t-clausen.dk
источник
Есть ли ;в начале вашего кода? Кажется, ты это посчитал.
Эрик Outgolfer
@EriktheGolfer Да, где есть сценарий до WITH. Компилятор выдаст ошибку, если она будет удалена. Можно проверить идеи в скрипке
t-clausen.dk
Я имею в виду, должно ли это быть в числе байтов общего источника? Потому что кажется, что он должен быть частью инструкции «Initial STDIN».
Эрик Outgolfer
@EriktheGolfer Я действительно не знаю, я полагаю, это может быть частью декларации. Также можно исключить мастер .. если в начале скрипта есть мастер USE. Но это дает раздражающее сообщение в скрипке.
t-clausen.dk
Я попытался поставить точку с запятой в предыдущей строке, и это сработало. Я предполагаю, что последняя строка имеет значение.
Эрик Outgolfer
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 ""))))

Ungolfed:

(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
rnso
источник
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];
Titus
источник
"!">$n=$s[$p]вместо того, чтобы " "==$n=$s[$p]сохранить один байт
Йорг Хюльсерманн
@ JörgHülsermann Это разрушит разрывы строк.
Тит
@ JörgHülsermann ... но трюк работает для сравнения звездочек (в новой версии)
Тит
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 (максимальное значение ячейки).

  • Мы можем превратить символ пробела в нулевой символ, используя ИЛИ-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;};
TheLethalCoder
источник
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]
Скайлер
источник