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


31

Простий конкурс, натхненний цим питанням про stackoverflow :

Вам дається зображення поверхні, сфотографованої супутником. Зображення являє собою растрову карту, де вода позначена символом " .", а земля позначена символом " *". Групи сусідніх *родовищ утворюють острів. (Два ' *' є суміжними, якщо вони є горизонтальними, вертикальними або діагональними сусідами). Ваше завдання - надрукувати кількість островів у растровій карті.

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

Зразок введення:

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

Вибірка зразка:

5

Winner - запис із найменшою кількістю байтів у коді.


Я не розумію логіки. Чи не 5 зірок у верхньому правому куті вважаються одним островом? Тоді ваш приклад має 4 острови.
14:00

екран не загортається. один острів у кожному з кутів + ​​самотній *острів
Клавдіу

2
Але за вашим визначенням, острів - це група символів '*', що передбачає більше одного.
аколіт

о справедливий пункт. окремі - *це також острови.
Клавдіу

Відповіді:


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' за допомогою заміни

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

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

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

островів

Білі квадрати відповідають клітинкам, що мають значення, 1.

На малюнку нижче показано кілька кроків, якими використовується підхід. Вхідна матриця містить лише 1's і 0' s. Вихідна матриця позначає кожен морфологічний кластер числом. (Я загорнув і вхідні, і вихідні матриці, MatrixFormщоб виділити їх двовимірну структуру.)

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

обробка

Max повертає найбільше число кластерів.


Відображення островів

Colorize пофарбує кожен острів унікально.

розфарбувати


Це не працює так, як написано на 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 або назву файлу на карті як перший аргумент командного рядка та друкує кількість островів для stdout. Використання базової рекурсивної заливки. Покращення вітаються як завжди!

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 символів

Читає карту від stdin. Не пощастило вдосконалити рекурсивну функцію заливки, 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);}

1

Пітон 2, 223 203 байт

Дякую Крок Хен та Арнольду Палмеру за відгалуження 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)))

Я вважав, що використання розуміння списку може зменшити кількість байтів, але це не забезпечило суттєвого покращення.

Спробуйте тут.

Я намагаюся обрізати його навколо російського списку (сусідів), але це не було успіхом. Можливо, хтось інший матиме якісь ідеї для цього розділу.


Ласкаво просимо до PPCG! Ось 217 байт , видаливши пробіли. Аналізатор Python справді поблажливий: P
Стівен

У вас більше пробілу, ніж потрібно. Видаліть прогалини між (s.index(l),i)і for, enumerate(l)і if, -v[0])<2і and, p=0:і p, і bool(x&n[p])і else. У вашій друкованій виписці також є більше дужок, ніж потрібно, оскільки у вас є дві групи set. Редагувати: Beat by StepHen, тому що робити речі на мобільному пристрої не ідеально.
Арнольд Палмер

203 байти, що поєднує мої пропозиції @ StepHen, а також трохи змінить умовні умови.
Арнольд Палмер

Дякую обом за допомогу! Поблажливість Python продовжує мене дивувати
:)

0

Perl 5 , 100 байт

98 байт коду + 2 байти для -p0прапорів.

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

Спробуйте в Інтернеті!

Адаптація (а точніше спрощення) моєї відповіді на виклик Скільки отворів? . Ви можете знайти пояснення того, як цей код працює в цій іншій відповіді (це пояснюється трохи довго, тому я вважаю за краще не повторювати цілі пояснення).



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

Порт моєї відповіді на скільки отворів? (так, я стрибаю на смузі, тепер, коли я бачив, як двоє інших людей переносять свої відповіді).


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.