Code-Golf: Count Islands

31

Un concurso simple, inspirado en esta pregunta de stackoverflow :

Se le da una imagen de una superficie fotografiada por un satélite. La imagen es un mapa de bits donde el agua está marcada con ' .' y la tierra está marcada con ' *'. Grupos de adyacentes *forman una isla. (Dos ' *' son adyacentes si son vecinos horizontales, verticales o diagonales). Su tarea es imprimir el número de islas en el mapa de bits.

Un single *también cuenta como una isla.

Entrada de muestra:

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

Salida de muestra:

5

El ganador es la entrada con el menor número de bytes en el código.

Claudiu
fuente
No entiendo la lógica. ¿No se consideran 5 estrellas en la esquina superior derecha como una isla? Entonces tu ejemplo tiene 4 islas.
defhlt
La pantalla no se ajusta. una isla en cada una de las esquinas + la *isla solitaria
Claudiu
2
Pero, según su definición, una isla es un grupo de caracteres '*', lo que implica más de uno.
acólito
oh punto justo los autónomos *también son islas.
Claudiu

Respuestas:

30

Mathematica 188 185 170 115 130 46 48 caracteres

Explicación

En versiones anteriores, hice un gráfico de posiciones que tenían una distancia del tablero de ajedrez de 1 entre sí. GraphComponentsLuego reveló el número de islas, una por componente.

La versión actual usa MorphologicalComponentspara encontrar y numerar grupos de unos en la matriz - regiones donde 1están físicamente contiguas. Debido a que las gráficas son innecesarias, esto resulta en una gran economía de código.


Código

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

Ejemplo

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

5 5


Cómo funciona

Los datos se ingresan como una matriz; en Mathematica, esta es una lista de listas.

En la matriz de entrada, los datos se convierten en 1'sy 0' s por el reemplazo

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

donde /.es una forma infija de ReplaceAllseguida por reglas de reemplazo. Básicamente, esto convierte la matriz en una imagen en blanco y negro. Todo lo que necesitamos hacer es aplicar la función Image,.

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

islas

Los cuadrados blancos corresponden a las celdas que tienen el valor, 1.

La siguiente imagen muestra algunos pasos que utiliza el enfoque. La matriz de entrada contiene solo 1'sy 0' s. La matriz de salida etiqueta cada grupo morfológico con un número. (Empaqueté las matrices de entrada y salida MatrixFormpara resaltar su estructura bidimensional).

MorphologicalComponentsreemplaza 1s con un número entero correspondiente al número de clúster de cada celda.

tratamiento

Max devuelve el número de clúster más grande.


Viendo las islas

Colorize coloreará cada isla de manera única.

colorear

DavidC
fuente
Esto no funciona como está escrito en v7 porque MorphologicalComponentsquiere un Image, pero incluso en v9 ¿no debería ser así Max@MorphologicalComponents[d/.{"."->0,"*"->1}]? Es decir, ¿el reemplazo se realiza primero? Maxdesaparecería antes de que se realizara el reemplazo, ¿no?
Mr.Wizard
Tengo V9, @ Mr.Wizard tiene razón. 46 caracteres es el número correcto.
Murta
@ Mr.Wizard El reemplazo se realiza antes de la aplicación de MorphologicalComponents. Debe ser una cosa de precedencia.
DavidC
Hola @DavidCarraher, mi punto no es sobre "->" sino que la expresión Max@MorphologicalComponents@d/.{"."->0,"*"->1}no funciona, lo que tiene sentido es Max@MorphologicalComponents[d /. {"." -> 0, "*" -> 1}], así que tienes un personaje más.
Murta
9

Ruby 1.9 (134 121 113 110)

Toma el mapa en stdin o el nombre del archivo del mapa como el primer argumento de línea de comando e imprime el número de islas para stdout. Usando un relleno de inundación recursivo básico. ¡Las mejoras son bienvenidas como siempre!

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

Al igual que el color de David, también puede hacer que muestre las diferentes islas cambiando $_[i]=?.a $_[i]=c.to_sy p chacia puts$_, lo que le daría algo como esto:

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

(¡al menos hasta que te quedes sin dígitos!)

Algunos casos de prueba:

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

5 5

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

9 9

*

1

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

2

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

3

Paul Prestidge
fuente
8
Me gusta la ultima prueba. ¡Pensando dentro de la caja!
Sr. Lister el
1

C, 169 caracteres

Lee el mapa de stdin. No tuve suerte de mejorar la función de relleno de inundación recursiva, r(j)aunque parece que podría 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
fuente
1

Python 2, 223 203 bytes

¡Gracias a Step Hen y Arnold Palmer por eliminar 20 caracteres de espacios y paréntesis innecesarios!

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

Pensé que usar las comprensiones de listas podría disminuir el número de bytes, pero no proporcionó ninguna mejora significativa.

Pruébalo aquí.

Sigo intentando recortarlo alrededor de la lista n (vecinos), pero no he tenido éxito. Quizás alguien más tenga algunas ideas para esa sección.

Solvacion
fuente
Bienvenido a PPCG! Aquí hay 217 bytes eliminando algunos espacios. El analizador de Python es muy indulgente: P
Stephen
Tiene más espacios en blanco de los necesarios. Elimine los espacios entre (s.index(l),i)y for, enumerate(l)y if, -v[0])<2y and, p=0:y p, y bool(x&n[p])y else. También tiene más paréntesis de los necesarios en su declaración impresa, ya que tiene 2 grupos alrededor set. Editar: Beat by StepHen porque hacer cosas en dispositivos móviles no es ideal.
Arnold Palmer el
203 bytes combinando @ StepHen's y mis sugerencias, además de cambiar un poco los condicionales.
Arnold Palmer el
¡Gracias a ambos por la ayuda! La clemencia de Python me sigue sorprendiendo
:)
0

Perl 5 , 100 bytes

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

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

Pruébalo en línea!

Una adaptación (o más bien una simplificación) de mi respuesta al desafío ¿Cuántos agujeros? . Puede encontrar explicaciones de cómo funciona este código en esta otra respuesta (es un poco largo de explicar, por lo que prefiero no volver a escribir las explicaciones completas).

Dada
fuente
0

Python 2, 233 bytes

Demasiado largo, en comparación con otras respuestas. Puerto de mi respuesta a esta pregunta .
Pruébalo en línea

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
Zarigüeya muerta
fuente
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}

Respuesta ES6 no competitiva (desafío de fechas posteriores al idioma) 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

Puerto de mi respuesta a ¿Cuántos agujeros? (Sí, estoy subiendo al carro, ahora que he visto a otras dos personas portar sus respuestas).

Neil
fuente
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))

Pruébalo en línea!

Keerthana Prabhakaran
fuente