Код-Гольф: Графские острова

31

Простое состязание, вдохновленное вопросом о переполнении стека :

Вам дается изображение поверхности, сфотографированной спутником. Изображение представляет собой растровое изображение, на котором вода помечена как « ., а земля помечена *». Группы соседей *образуют остров. (Два ' *' смежны, если они являются соседями по горизонтали, вертикали или диагонали). Ваша задача - напечатать количество островов в растровом изображении.

Сингл *также считается островом.

Пример ввода:

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

Пример вывода:

5

Победителем становится запись с наименьшим количеством байтов в коде.

Клаудиу
источник
Я не понимаю логику. Разве 5 звезд в верхнем правом углу не считаются одним островом? Тогда ваш пример имеет 4 острова.
defhlt
экран не заворачивается один остров в каждом из углов + одинокий *остров
Клаудиу
2
Но по вашему определению остров - это группа символов «*», подразумевающая более одного.
помощник
о честно автономные *s также острова.
Клавдиу

Ответы:

30

Mathematica 188 185 170 115 130 46 48 символов

объяснение

В более ранних версиях я строил график позиций с расстоянием шахматной доски 1 друг от друга. GraphComponentsзатем выявлено количество островов, по одному на компонент.

Настоящая версия использует MorphologicalComponentsдля поиска и нумерации кластеров единиц в массиве - области, где 1они физически смежны. Поскольку в графике нет необходимости, это приводит к огромной экономии кода.


Код

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

пример

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

5


Как это работает

Данные вводятся в виде массива; в Mathematica это список списков.

Во входном массиве данные преобразуются в 1's 0' и 's' путем замены.

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

где /.- инфиксная форма, за которой ReplaceAllследуют правила замены. Это по существу преобразует массив в черно-белое изображение. Все, что нам нужно сделать, это применить функцию Image.

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

острова

Белые квадраты соответствуют ячейкам, имеющим значение 1.

На рисунке ниже показаны некоторые шаги, которые использует этот подход. Входная матрица содержит только 1«и 0». Выходная матрица маркирует каждый морфологический кластер числом. (Я обернул входную и выходную матрицы, MatrixFormчтобы выделить их двумерную структуру.)

MorphologicalComponentsзаменяет 1s на целое число, соответствующее номеру кластера каждой ячейки.

обработка

Max возвращает наибольшее число кластеров.


Отображение островов

Colorize раскрасит каждый остров по-своему.

раскрасить

DavidC
источник
Это не работает, как написано на v7, потому что MorphologicalComponentsхочет Image, но даже на v9 это не должно быть Max@MorphologicalComponents[d/.{"."->0,"*"->1}]? То есть замена сделана первой? Maxисчезнет до того, как замена будет сделана, не так ли?
Mr.Wizard
У меня есть V9, @ Mr.Wizard прав. 46 символов это правильный номер.
Мурта
@ Mr.Wizard Замена выполняется перед применением MorphologicalComponents. Должно быть приоритетом.
DavidC
Привет @DavidCarraher, моя точка зрения не о "->", но о том, что выражение Max@MorphologicalComponents@d/.{"."->0,"*"->1}не работает, что имеет смысл Max@MorphologicalComponents[d /. {"." -> 0, "*" -> 1}], так что у вас есть еще один символ.
Мурта
9

Рубин 1.9 (134 121 113 110)

Принимает карту в stdin или имя файла карты в качестве первого аргумента командной строки и печатает количество островов в стандартный вывод. Используя базовую рекурсивную заливку. Улучшения приветствуются как всегда!

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

Подобно раскрасить Давид, вы также можете получить его для отображения различных островов, изменяя $_[i]=?.к $_[i]=c.to_sи p cк puts$_, который даст вам что - то вроде этого:

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

(по крайней мере, пока у вас не кончатся цифры!)

Некоторые тестовые случаи:

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

5

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

9

*

1

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

2

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

3

Пол Престиж
источник
8
Мне нравится последний тест. Мышление внутри коробки!
Мистер Листер
1

C 169 символов

Читает карту со стандартного ввода. Не повезло в улучшении рекурсивной функции заливки, r(j)хотя похоже, что так и могло быть.

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
источник
1

Python 2, 223 203 байта

Спасибо Step Hen и Арнольду Палмеру за то, что вы сбрили 20 символов пробелов и лишние скобки!

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

Я думал, что использование списочных пониманий может уменьшить количество байтов, но это не дало существенного улучшения.

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

Я продолжаю пытаться обрезать его по списку n (соседей), но у меня ничего не получилось. Возможно, у кого-то еще будут какие-то идеи для этого раздела.

Сольватация
источник
Добро пожаловать в PPCG! Вот 217 байт , удалив несколько пробелов. Парсер Python действительно снисходительный: P
Стивен
У вас больше пробелов, чем нужно. Уберите пробелы между (s.index(l),i)и for, enumerate(l)и if, -v[0])<2и and, p=0:и p, и bool(x&n[p])и else. У вас также есть больше скобок, чем необходимо в вашем операторе печати, так как у вас есть 2 окружающие группы set. Edit: Beat by StepHen, потому что делать вещи на мобильном телефоне не идеально.
Арнольд Палмер
203 байта, сочетающие @ StepHen's и мои предложения, плюс немного измененные условия.
Арнольд Палмер
Спасибо вам обоим за помощь! Снисходительность Пайтона продолжает удивлять меня:)
сольватации
0

Perl 5 , 100 байт

98 байт кода + 2 байта для -p0флагов.

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

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

Адаптация (или, скорее, упрощение) моего ответа на вызов « Сколько отверстий»? , Вы можете найти объяснения того, как этот код работает с другим ответом (объяснение немного длинное, поэтому я предпочитаю не перепечатывать все объяснения полностью).

папа
источник
0

Python 2, 233 байта

Слишком долго, по сравнению с другими ответами. Порт моего ответа на этот вопрос .
Попробуйте онлайн

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
Мертвый Опоссум
источник
0

JavaScript, 158 байт

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}

Неконкурентный ответ ES6 (вызов языковых постдатов) для 132 байтов:

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

Порт моего ответа на Сколько дырок? (да, я прыгаю на подножку, теперь, когда я видел, как два других человека портируют свои ответы).

Нил
источник
0

Python 2 , 225 байт

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

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

Киртана Прабхакаран
источник