Code-Golf: Ilhas Count

31

Um concurso simples, inspirado nesta pergunta do stackoverflow :

Você recebe uma imagem de uma superfície fotografada por um satélite. A imagem é um bitmap em que a água é marcada por ' .' e a terra é marcada por ' *'. Grupos de adjacentes *formam uma ilha. (Dois ' *' são adjacentes se forem vizinhos horizontais, verticais ou diagonais). Sua tarefa é imprimir o número de ilhas no bitmap.

Um single *também conta como uma ilha.

Entrada de amostra:

.........**
**......***
...........
...*.......
*........*.
*.........*

Saída de amostra:

5

O vencedor é a entrada com o menor número de bytes no código.

Claudiu
fonte
Eu não entendo a lógica. Não são consideradas 5 estrelas no canto superior direito como uma ilha? Então seu exemplo tem 4 ilhas.
usar o seguinte código
a tela não quebra. uma ilha em cada um dos cantos + a solitária *ilha
Claudiu
2
Mas, por sua definição, uma ilha é um grupo de caracteres '*', implicando mais de um.
Acolito
oh ponto justo. *s independentes também são ilhas.
Claudiu

Respostas:

30

Mathematica 188 185 170 115 130 130 46 48 caracteres

Explicação

Nas versões anteriores, fiz um gráfico de posições com uma distância de 1 no tabuleiro de xadrez. GraphComponentsdepois revelou o número de ilhas, uma por componente.

A presente versão usa MorphologicalComponentspara encontrar e numerar clusters de unidades no array - regiões onde 1são fisicamente contíguas. Como os gráficos são desnecessários, isso resulta em uma enorme economia de código.


Código

Max@MorphologicalComponents[#/.{"."->0,"*"->1}]&

Exemplo

Max@MorphologicalComponents[#/.{"."->0,"*"->1}]&[{{".", ".", ".", ".", ".", ".", ".", ".", ".", "*", "*"}, {"*", "*", ".", ".", ".", ".", ".", ".", "*", "*", "*"}, {".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "."}, {".", ".", ".", "*", ".", ".", ".", ".", ".", ".", "."}, {"*", ".", ".", ".", ".", ".", ".", ".", ".", "*", "."}, {"*", ".", ".", ".", ".", ".", ".", ".", ".", ".", "*"}}]

5


Como funciona

Os dados são inseridos como uma matriz; no Mathematica, esta é uma lista de listas.

Na matriz de entrada, os dados são convertidos em 1's 0' pela substituição

/.{"."->0,"*"->1}

onde /.é uma forma infix ReplaceAllseguida por regras de substituição. Isso basicamente converte a matriz em uma imagem em preto e branco. Tudo o que precisamos fazer é aplicar a função Image,.

Image[{{".", ".", ".", ".", ".", ".", ".", ".", ".", "*", "*"}, {"*", "*", ".", ".", ".", ".", ".", ".", "*", "*", "*"}, {".", ".", ".", ".", ".", ".", ".", ".", ".", ".", "."}, {".", ".", ".", "*", ".", ".", ".", ".", ".", ".", "."}, {"*", ".", ".", ".", ".", ".", ".", ".", ".", "*", "."}, {"*", ".", ".", ".", ".", ".", ".", ".", ".", ".", "*"}} /. {"." -> 0, "*" -> 1}]

ilhas

Os quadrados brancos correspondem às células com o valor 1.

A figura abaixo mostra alguns passos que a abordagem usa. A matriz de entrada contém apenas 1's e 0' s. A matriz de saída rotula cada cluster morfológico com um número. (Coloquei as matrizes de entrada e saída MatrixFormpara destacar sua estrutura bidimensional.)

MorphologicalComponentssubstitui 1s por um número inteiro correspondente ao número do cluster de cada célula.

em processamento

Max retorna o maior número de cluster.


Exibindo as Ilhas

Colorize colorirá cada ilha exclusivamente.

colorir

DavidC
fonte
Isso não está funcionando como está escrito na v7 porque MorphologicalComponentsquer um Image, mas mesmo na v9 não deveria ser Max@MorphologicalComponents[d/.{"."->0,"*"->1}]? Ou seja, a substituição é feita primeiro? Maxdesapareceria antes da substituição, não seria?
precisa saber é o seguinte
Eu tenho V9, @ Mr.Wizard está certo. 46 caracteres é o número certo.
Murta
@ Mr.Wizard A substituição é realizada antes da aplicação dos Componentes Morfológicos. Deve ser uma coisa de precedência.
DavidC
Olá @DavidCarraher, meu argumento não é sobre "->", mas que a expressão Max@MorphologicalComponents@d/.{"."->0,"*"->1}não funciona, o que faz sentido Max@MorphologicalComponents[d /. {"." -> 0, "*" -> 1}], então você tem mais um caractere.
Murta
9

Ruby 1.9 (134 121 113 110)

Pega o mapa em stdin ou o nome do arquivo do mapa como o primeiro argumento da linha de comando e imprime o número de ilhas em stdout. Usando um preenchimento recursivo básico. Melhorias bem-vindas como sempre!

c=0
gets$!
c+=1while(f=->i{9.times{|o|$_[i]=?.;f[o]if$_[o=i+(o/3-1)*(~/$/+1)+o%3-1]==?*&&o>0}if i})[~/\*/]
p c

Semelhante à coloração de David, você também pode exibir as diferentes ilhas alterando $_[i]=?.para $_[i]=c.to_se p cpara puts$_, o que forneceria algo assim:

.........00
11......000
...........
...2.......
3........4.
3.........4

(pelo menos até você ficar sem dígitos!)

Alguns casos de teste:

.........**
**......***
...........
...*.......
*........*.
*.........*

5

......*..**....*
**...*..***....*
....*..........*
...*.*.........*
*........***....
*.....*...***...
*.....*...*....*
****..........**
*.........*.....

9

*

1

****
****
....
****

2

**********
*........*
*.******.*
*.*....*.*
*.*.**.*.*
*.*.**.*.*
*.*....*.*
*.******.*
*........*
**********

3

Paul Prestidge
fonte
8
Eu gosto do último teste. Pensando dentro da caixa!
Sr. Lister
1

C, 169 caracteres

Lê o mapa de stdin. Não teve sorte em melhorar a função recursiva de preenchimento de inundação, r(j)embora pareça que poderia ser.

c,g,x,w;char m[9999];r(j){if(m[j]==42)m[j]=c,r(j+1),r(j+w-1),r(j+w),r(j+w+1),c+=j==g;}main(){while((m[x++]=g=getchar())+1)w=g<11*!w?x:w;for(;g++<x;)r(g);printf("%i",c);}
schnaader
fonte
1

Python 2, 223 203 bytes

Obrigado a Step Hen e Arnold Palmer por cortar 20 caracteres de espaços e parênteses desnecessários!

s=input()
c=[(s.index(l),i)for l in s for i,v in enumerate(l)if'*'==v]
n=[set([d for d in c if-2<d[0]-v[0]<2and-2<d[1]-v[1]<2])for v in c]
f=lambda x,p=0:p if x&n[p]else f(x,p+1)
print len(set(map(f,n)))

Eu pensei que o uso da compreensão da lista poderia diminuir o número de bytes, mas não forneceu nenhuma melhoria significativa.

Experimente aqui.

Continuo tentando recortá-lo na lista n (vizinhos), mas não obtive sucesso. Talvez alguém tenha algumas idéias para essa seção.

Solvação
fonte
Bem-vindo ao PPCG! Aqui estão 217 bytes removendo alguns espaços. O analisador Python é realmente branda: P
Stephen
Você tem mais espaço em branco do que o necessário. Remova os espaços entre (s.index(l),i)e for, enumerate(l)e if, -v[0])<2e and, p=0:e p, e bool(x&n[p])e else. Você também tem mais parênteses do que o necessário na sua declaração impressa, já que possui 2 grupos ao redor set. Edit: Beat by StepHen porque fazer coisas no celular não é o ideal.
Arnold Palmer
203 bytes combinando o @ StepHen e minhas sugestões, além de alterar um pouco os condicionais.
Arnold Palmer
Agradeço a ambos pela ajuda! Clemência da Python me mantém surpreendente:)
Solvation
0

Perl 5 , 100 bytes

98 bytes de código + 2 bytes para -p0sinalizadores.

/.*/;$@="@+"-1;$~="(.?.?.{$@})?";(s/X$~\*/X$1X/s||s/\*$~X/X$1X/s)&&redo;s/\*/X/&&++$\&&redo}{$\|=0

Experimente online!

Uma adaptação (ou melhor, uma simplificação) da minha resposta ao desafio Quantos buracos? . Você pode encontrar explicações sobre como esse código funciona nessa outra resposta (é um pouco longo para explicar, então prefiro não redigitar todas as explicações).

dada
fonte
0

Python 2, 233 bytes

Muito tempo, em comparação com outras respostas. Porto da minha resposta a esta pergunta .
Experimente online

A=input()
c=0
X=len(A[0])-1
Y=len(A)-1
def C(T):
 x,y=T
 if A[y][x]<'.':A[y][x]='.';map(C,zip([x]*3+[min(x+1,X)]*3+[max(x-1,0)]*3,[y,min(y+1,Y),max(y-1,0)]*3))
while'*'in sum(A,[]):i=sum(A,[]).index('*');c+=1;C((i%-~X,i/-~X))
print c
Gambá morto
fonte
0

JavaScript, 158 bytes

function f(s){w=s.search('\n');t=s.replace(RegExp('([*@])([^]{'+w+','+(w+2)+'})?(?!\\1)[*@]'),'@$2@');return t!=s?f(t):/\*/.test(s)?f(s.replace('*','@'))+1:0}

Resposta ES6 não-competitiva (desafio de pós-datas de idiomas) para 132 bytes:

f=s=>s!=(s=s.replace(RegExp(`([*@])([^]{${w=s.search`
`},${w+2}})?(?!\\1)[*@]`),`@$2@`))?f(s):/\*/.test(s)?f(s.replace(`*`,`@`))+1:0

Porto da minha resposta para Quantos Buracos? (sim, eu estou pulando na onda, agora que eu vi duas outras pessoas portando suas respostas).

Neil
fonte
0

Python 2 , 225 bytes

g=map(list,input())
q,w,t,r=len(g),len(g[0]),0,range
def l(i,j):
 if 0<=i<q and 0<=j<w and g[i][j]=='1':g[i][j]=0;l(i+1,j);l(i-1,j);l(i,j+1);l(i,j-1)
 return 1
print sum(l(i,j)if g[i][j]=='1'else 0 for j in r(w)for i in r(q))

Experimente online!

Keerthana Prabhakaran
fonte