Code-Golf: Count Islands

31

Ein einfacher Wettbewerb, inspiriert von dieser Stackoverflow-Frage :

Sie erhalten ein Bild einer Oberfläche, die von einem Satelliten fotografiert wurde. Das Bild ist eine Bitmap, auf der Wasser mit " ." und Land mit " *" markiert ist . Gruppen benachbarter *'s bilden eine Insel. (Zwei ' *' sind benachbart, wenn es sich um horizontale, vertikale oder diagonale Nachbarn handelt.) Ihre Aufgabe ist es, die Anzahl der Inseln in der Bitmap zu drucken.

Eine Single *zählt auch als Insel.

Beispiel Input:

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

Beispielausgabe:

5

Gewinner ist der Eintrag mit der kleinsten Anzahl von Bytes im Code.

Claudiu
quelle
Ich verstehe die Logik nicht. Werden nicht 5 Sterne in der rechten oberen Ecke als eine Insel angesehen? Dann hat Ihr Beispiel 4 Inseln.
14.
Der Bildschirm wird nicht gewickelt. eine Insel in jeder Ecke + die einsame *Insel
Claudiu
2
Aber Ihrer Definition nach ist eine Insel eine Gruppe von '*' - Zeichen, die mehr als eines implizieren.
Akolyth
oh fair point. eigenständige *s sind auch inseln.
Claudiu

Antworten:

30

Mathematica 188 185 170 115 130 46 48 Zeichen

Erläuterung

In früheren Versionen habe ich ein Diagramm mit Positionen erstellt, die einen Schachbrettabstand von 1 voneinander haben. GraphComponentsDann ergab sich die Anzahl der Inseln, eine pro Komponente.

In der vorliegenden Version werden MorphologicalComponentsGruppen von Gruppen in den Array - Regionen gefunden und nummeriert, in denen sie 1physikalisch zusammenhängen. Da keine grafischen Darstellungen erforderlich sind, ergibt sich eine enorme Codeeinsparung.


Code

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

Beispiel

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

5


Wie es funktioniert

Daten werden als Array eingegeben; In Mathematica ist dies eine Liste von Listen.

Im Eingabearray werden die Daten durch die Ersetzung in 1's und 0' s konvertiert

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

Wo /.ist ein Infix von ReplaceAllgefolgt von Ersetzungsregeln. Dadurch wird das Array im Wesentlichen in ein Schwarzweißbild umgewandelt. Alles was wir tun müssen, ist die Funktion anzuwenden Image.

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

Inseln

Die weißen Quadrate entsprechen den Zellen mit dem Wert 1.

Das Bild unten zeigt einige Schritte, die der Ansatz verwendet. Die Eingabematrix enthält nur 1's und 0' s. Die Ausgabematrix kennzeichnet jeden morphologischen Cluster mit einer Nummer. (Ich habe sowohl die Eingabe- als auch die Ausgabematrizen eingewickelt MatrixForm, um ihre zweidimensionale Struktur hervorzuheben.)

MorphologicalComponentsErsetzt 1s durch eine Ganzzahl, die der Clusternummer jeder Zelle entspricht.

wird bearbeitet

Max Gibt die größte Clusternummer zurück.


Anzeigen der Inseln

Colorize färbt jede Insel einzigartig.

kolorieren

DavidC
quelle
Dies funktioniert nicht so, wie es auf v7 geschrieben wurde, weil man es MorphologicalComponentswill Image, aber sollte es nicht auch auf v9 sein Max@MorphologicalComponents[d/.{"."->0,"*"->1}]? Das heißt, der Austausch erfolgt zuerst? Maxwürde verschwinden, bevor der Austausch durchgeführt wurde, nicht wahr?
Mr.Wizard
Ich habe V9, @ Mr.Wizard hat recht. 46 Zeichen sind die richtige Zahl.
Murta
@ Mr.Wizard Der Austausch erfolgt vor dem Einsatz von MorphologicalComponents. Muss Vorrang haben.
DavidC
Hallo @DavidCarraher, mein Punkt ist nicht "->", aber dass der Ausdruck Max@MorphologicalComponents@d/.{"."->0,"*"->1}nicht funktioniert, was Sinn macht Max@MorphologicalComponents[d /. {"." -> 0, "*" -> 1}], ist , dass du noch ein Zeichen hast.
Murta
9

Ruby 1.9 (134 121 113 110)

Nimmt die Karte in Standard oder den Dateinamen der Karte als erstes Befehlszeilenargument und gibt die Anzahl der Inseln in Standard aus. Verwenden einer rekursiven Grundfüllung. Verbesserungen wie immer willkommen!

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

Ähnlich wie bei Davids Kolorierung können Sie auch die verschiedenen Inseln anzeigen, indem Sie $_[i]=?.zu $_[i]=c.to_sund p czu wechseln puts$_, was ungefähr so ​​aussieht:

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

(Zumindest bis dir die Ziffern ausgehen!)

Einige Testfälle:

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

5

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

9

*

1

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

2

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

3

Paul Prestidge
quelle
8
Ich mag den letzten Test. Denken in der Kiste!
Mr Lister
1

C 169 Zeichen

Liest die Karte von stdin. Hatte kein Glück, die rekursive Füllfunktion zu verbessern, r(j)obwohl es so aussieht, als könnte es sein.

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
quelle
1

Python 2, 223 203 Bytes

Vielen Dank an Step Hen und Arnold Palmer für das Abschneiden von 20 Leerzeichen und unnötigen Klammern!

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

Ich dachte, dass die Verwendung von Listenverständnissen die Anzahl der Bytes verringern könnte, aber dies brachte keine signifikante Verbesserung.

Probieren Sie es hier aus.

Ich versuche immer wieder, es um die n (Nachbarn) Liste zu kürzen, aber ich war nicht erfolgreich. Vielleicht hat jemand anderes Ideen für diesen Abschnitt.

Lösung
quelle
Willkommen bei PPCG! Hier sind 217 Bytes, indem einige Leerzeichen entfernt werden. Der Python-Parser ist wirklich nachsichtig: P
Stephen
Sie haben mehr Leerzeichen als nötig. Entfernen Sie die Räume zwischen (s.index(l),i)und for, enumerate(l)und if, -v[0])<2und and, p=0:und p, und , bool(x&n[p])und else. Sie haben auch mehr Klammern als in Ihrer Druckanweisung benötigt, da Sie 2 Gruppen umgeben set. Edit: Beat by StepHen, weil es nicht ideal ist, Sachen auf dem Handy zu machen.
Arnold Palmer
203 Bytes, die @ StepHens und meine Vorschläge kombinieren, plus ein wenig die Bedingungen ändern.
Arnold Palmer
Vielen Dank für die Hilfe! Pythons Nachsicht überrascht mich immer wieder
:)
0

Perl 5 , 100 Bytes

98 Byte Code + 2 Byte für -p0Flags.

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

Probieren Sie es online!

Eine Anpassung (oder eher eine Vereinfachung) meiner Antwort auf die Herausforderung Wie viele Löcher? . Erklärungen zur Funktionsweise dieses Codes finden Sie in dieser anderen Antwort (die Erklärung ist etwas lang, daher ziehe ich es vor, nicht die gesamten Erklärungen erneut einzugeben).

Dada
quelle
0

Python 2, 233 Bytes

Im Vergleich zu anderen Antworten zu lang. Port meiner Antwort auf diese Frage .
Probieren Sie es online aus

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
Totes Opossum
quelle
0

JavaScript, 158 Byte

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}

Nicht konkurrierende ES6-Antwort (Sprachnachstellung) für 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

Port meiner Antwort auf Wie viele Löcher? (Ja, ich springe auf den Zug, jetzt, wo ich gesehen habe, dass zwei andere Leute ihre Antworten portieren).

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

Probieren Sie es online!

Keerthana Prabhakaran
quelle