穴はいくつありますか?


17

チャレンジ

図形のグラフィカルな入力が与えられたら、その穴の数を決定します。

重複しない

この質問は、カウントアイランドの重複としてマークされました。このチャレンジは、カウントアイランドチャレンジとは異なると考えています。なぜなら、このチャレンジでは、国境に接するブロックを排除する方法を理解する必要があるからです。

入力

入力は、複数行の文字列、文字列の配列、または文字配列の配列のいずれかの入力の2D形式として与えられます。これは形状を表します。形状は、エッジで接続された1つのピースのみであることが保証されています。入力方法を指定してください。

出力

出力は、形状にいくつの穴があるかを示す単一の整数です。末尾の改行は許可されますが、他の先頭または末尾の空白は許可されません。つまり、出力は正規表現と一致する必要があります^\d+\n?$

穴とは何ですか?

これらは単一の穴です。

####
#  #
#  #
####

####
#  #
# ##
###

#####
# # #
#   #
#####

これらは穴ではありません:

########
########
#   ####
#   ####
# ######
#       
########

###
#  
###

##########
#         
# ########
# #      #
# # #### #
# #   ## #
# ###### #
#        #
##########

ほとんど、ギャップが外側のエッジにつながっている場合、それは穴ではありません。

テストケース

#####
# # # -> 2
#####

#####
#    
# ### -> 1
# # #
#####

####
## # -> 1 (things are connected by edges)
# ##
####

###
### -> 0 (You must handle shapes with no holes, but input will always contain at least one filled space)
###

「#」の代わりに、スペースの代わりに任意の文字を使用できます。

客観的スコアリング基準

スコアは、プログラムのバイト数として与えられます。

勝ち

勝者は、4月4日までに最低スコアの提出物になります。



2
###|# #|## テストケースとして追加できますか?それは0正しいはずですよね?
マーティンエンダー


1
可能性のある重複したコード-ゴルフ:島カウント
マシュー盧

@SIGSEGVそれを指摘してくれてありがとう。ただし、この課題には他の課題とは十分に異なる独自の投稿を保証する重要な要素があると思います(違いを編集しました)。ご意見をお聞かせください。必要に応じて、チャットでディスカッションを開始できます。
ハイパーニュートリノ

回答:


12

MATLAB /オクターブ、18バイト

@(g)1-bweuler(g,4)

オンラインでお試しください!

これは、入力として論理行列を取る匿名関数です。オブジェクトはtrue(指定された接続性を持つ)エントリによって形成され、空のスペースはfalseエントリです。

bweuler 次に、そのマトリックスで表されるバイナリイメージのオイラー数、つまりオブジェクトの数から穴の数を引いた数を計算します。


8

Mathematica、59 57バイト

1/.ComponentMeasurements[#,"Holes",CornerNeighbors->0>1]&

そのためのビルトインがあります。入力を1s(壁)と0s(穴)の2Dマトリックスとして受け取ります。便宜上、この入力形式のすべてのテストケースを以下に示します。

{{{1,1,1,1},{1,0,0,1},{1,0,0,1},{1,1,1,1}},
 {{1,1,1,1},{1,0,0,1},{1,0,1,1},{1,1,1,0}},
 {{1,1,1,1,1},{1,0,1,0,1},{1,0,0,0,1},{1,1,1,1,1}},
 {{1,1,1,1,1,1,1,1},{1,1,1,1,1,1,1,1},{1,0,0,0,1,1,1,1},{1,0,0,0,1,1,1,1},{1,0,1,1,1,1,1,1},{1,0,0,0,0,0,0,0},{1,1,1,1,1,1,1,1}},
 {{1,1,1},{1,0,0},{1,1,1}},
 {{1,1,1,1,1,1,1,1,1,1},{1,0,0,0,0,0,0,0,0,0},{1,0,1,1,1,1,1,1,1,1},{1,0,1,0,0,0,0,0,0,1},{1,0,1,0,1,1,1,1,0,1},{1,0,1,0,0,0,1,1,0,1},{1,0,1,1,1,1,1,1,0,1},{1,0,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1}},
 {{1,1,1,1,1},{1,0,1,0,1},{1,1,1,1,1}},
 {{1,1,1,1,1},{1,0,0,0,0},{1,0,1,1,1},{1,0,1,0,1},{1,1,1,1,1}},
 {{1,1,1,1},{1,1,0,1},{1,0,1,1},{1,1,1,1}}}

代替ソリューション、59バイト

これは私の最初のアプローチでした。また、コンポーネント関連のビルトインに基づいていますが、穴を直接カウントしません(代わりに、穴自体をコンポーネントとして扱います)。

Max@*MorphologicalComponents@*DeleteBorderComponents@*Image

上記と同じ入力形式を使用しますが、0sと1sの役割を交換します。

これをImage最初に変換する必要があるのは、それ以外の場合、Mathematicaはすべての1-cellsを単一のコンポーネントの一部と見なすからです(マトリックスをコンポーネントラベルマトリックスとして扱うため)。したがって、もしあれば1 -cellがマージンに接している、それらはすべて削除されます。いつDeleteBorderComponents代わりにイメージで使用される、暗黙的な接続チェックを実行してコンポーネントを見つけます。

あるいは、MorphologicalComponents firstを呼び出して入力を適切なラベルマトリックスに変換することもできますが、DeleteBorderComponents2番目に行うと、最大コンポーネントラベルがコンポーネントの数に対応することは保証されなくなります(より小さいコンポーネントを削除する可能性があるため)。


5
本当に、Mathematicaは...ちょうどすべてのためのビルトインを持っている
氏Xcoder

3
@ Mr.Xcoder良いチャレンジのアイデアがあります:Mathematicaに組み込み機能がないチャレンジを見つけてください。
ハイパーニュートリノ

@HyperNeutrino良いアイデアですが、残念ながらMathematicaのユーザーはそれを大幅に下げると思うし、コミュニティがうまく反応するかどうかはわかりません... =]
Xcoder氏17年

1
@HyperNeutrino、おそらくそのための組み込みもあります:
ブライアンミントン

@BrianMintonハハ。おそらくMathematicaにはが組み込まれていGenerateBuiltinます。ビルトインを持たないチャレンジに対してビルトインを生成します。また、私はそうしたい場合は、のは、この議論を続けましょう、マーティン・エンダーの受信トレイに悪い感じ、ここで
HyperNeutrino

4

Perl 5 5、154バイト

152バイトのコード+ -p0フラグ用の2バイト。

s/^ | $/A/gm;s/^.*\K | (?=.*$)/A/&&redo;/.*/;$@="@+"-1;for$%(A,X){$~="(.?.?.{$@})?";(s/$%$~ /$%$1$%/s||s/ $~$%/$%$1$%/s)&&redo}s/ /X/&&++$\&&redo}{$\|=0

オンラインでお試しください!

コードは一目瞭然だと思います。


理解するためにいくつかの説明が必要な場合は、単純な入力でプログラムによって実行される変換のいくつかのステップがあります( ここます))で、その後にいくつかの説明が続き。

######
#     
#####
###
#####
######

######
#A
#####
###
#####
######

######
#AAAAA
#A ####
#A##
#####
######

######
#AAAAA
#A ####
#A#X#
#####
######

######
#AAAAA
#A ####
#A#XX#
####バツ#
######

最初s/^ | $/A/gm;s/^.*\K | (?=.*$)/A/&&redoに、境界内のスペース(左/右に1番目の正規表現、下/上に2番目の正規表現)をA(この文字を非常に任意に選択します)に置き換えます。
次に、で形状の幅を取得し/.*/;$@="@+"-1;ます。
今、私たちが接続されているすべてのスペース交換したいAとしAた空間が接続されている場合ので(A、それが穴の一部にすることはできませんを意味します。それはによって行われますfor$%(A,X){(s/$%(.?.?.{$@})? /$%$1$%/s||s/ (.?.?.{$@})?$%/$%$1$%/s)&&redo}。(あなたはこれが行われることに気づくでしょう以下のためいったんAsおよびのための1つXのS -についての説明X)怒鳴る二つの正規表現がここにあります。s/$%(.?.?.{$@})? /$%$1$%/sの右または下にあるスペースを扱ってAます。s/ (.?.?.{$@})?$%/$%$1$%/s一番上のスペースにまたはの左側A
この時点で、文字列に残っているスペースは穴の一部のみです。
まだスペースがありますが、繰り返します:
-ホールの量を知るために、スペースをXs/ /X/)に置き換えて、ホールのカウンターを増分し($\++)、プログラム全体をやり直します(実際には、forループだけをやり直します、ただし、プログラム全体をやり直す方がバイト数が少なくなります)。
-その後、forループは、aに接続されているすべてのスペースを同じ穴の一部であるため、a Xで置き換えXます。
最後に、$\|=0穴がない場合0、空の文字列の代わりにa が印刷されるようにします。そして、$\暗黙のうちに感謝印刷されて-pフラグを。


4

Python 2、282バイト

斜めのタッチTT_TTを処理するには+100(本当に必要ですか?)
-119 @Rodガイダンスのおかげで:)

オンラインでお試しください。入力として文字「#」と空白の配列の配列を取ります。

A=input()
c=0
X=len(A[0])-1
Y=len(A)-1
def C(T):
 x,y=T
 global g
 if A[y][x]<'#':
    if y<1or y==Y or x<1or x==X:g=0
    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(' ');g=1;C((i%-~X,i/-~X));c+=g
print c

最初の空白を検索し、空でない( '#')としてマークします。すべての空のセルを埋めながら、周囲のすべてを再帰的にチェックします。現在の「穴」の空のセルがボーダーカウンター上にあるように見える場合、それは変更されません。


1
使用sum(A,[])して平らにすることができます
ロッド

1
また、あなたは確認することができ、この答えを、それは同じ再帰的なロジックを持ち、また、(最初の行に「名前の変更」機能のような)他のいくつかのトリックを持っている
ロッド

@Rod Trick with sumはとても良いです、ありがとう。私は現在、このthisいことなく8つの方向すべてを取得することに取り組んでいます。あなたの答えが役立つかもしれません。その後更新します
デッドポッサム

私の答えでは、より少ないバイトを使用するためにリスト内包内で再帰関数を呼び出しましたが、あなたの場合、リストの長さをチェックして、現在のセルが境界に属しているかどうかを確認できます(リストの内容はNones、しかしそれは無関係です)
ロッド

1
あなたは上の開梱リストを使用することができますx=T[0];y=T[1]- > x,y=T、あなたは(おそらく)宣言する必要はありませんg=13行目には、あなたが使用することができます<>(それが取るの文字列を比較するために、ord()あなたは、交換することができ、各文字の値を)A[y][x]!='#'してA[y][x]<'#'いるので、' '<'#'
ロッド

3

Python 2、233 225 222バイト

math_junkie:-8バイト

入力としてブール値/整数(0/1)の2D配列を受け取ります

s=input()
o=[-1,0,1]
m=lambda x,y:0if x in[-1,len(s[0])]or y in[-1,len(s)]else 1if s[y][x]else(s[y].__setitem__(x,1),all([m(x+a,y+b)for a in o for b in o]))[1]
e=enumerate
print sum(m(x,y)-c for y,l in e(s)for x,c in e(l))

オンラインでお試しください!

フォーマット済みバージョン:

s = input()
o = [-1, 0, 1]
m = lambda x,y:
    0 if x in [-1, len(s[0])] or y in [-1, len(s)]
      else
        1 if s[y][x]
          else
            (s[y].__setitem__(x, 1),
             all([m(x + a, y + b) for a in o for b in o]))[1]
e = enumerate
print sum(m(x, y) - c for y, l in e(s) for x, c in e(l))

1
あなたが数バイトを保存することができますprint sum(m(x,y)...代わりにa=print a
数学中毒

1
また、いくつかのマイナーなホワイトスペースゴルフ:TIO
数学中毒者

1

C#7、364バイト

これに満足していない...多分他の誰かがそれを整理できるかもしれません...後でエネルギーがあれば、最初のループを反転し、それが境界チェックのトリミングに役立つかどうかを確認します。

using C=System.Console;class P{static void Main(){string D="",L;int W=0,H=0,z;for(;(L=C.ReadLine())!=null;H+=W=L.Length)D+=L;int[]S=new int[H*9];int Q(int p)=>S[p]<p?Q(S[p]):p;void R(int r)=>S[Q(r+=z)]=S[r]>0?z:0;for(z=H;z-->0;)if(D[z]<33){S[z]=z;R(1);R(W);R(W+1);R(W-1);}for(;++z<H;)S[Q(z)]*=z>H-W-2|z%W<1|z%W>W-2?0:1;for(;W<H;)z+=Q(W)<W++?0:1;C.WriteLine(z-H);}}

オンラインで試す

完全なプログラム、標準入力への入力、標準出力への出力を受け入れます。ばらばらのセットを使用して暫定的な穴を決定し、境界をタッチで殺すとき(トップエッジに多少の危険を伴う)。

書式設定されコメントされたコード:

using C=System.Console;

class P
{
    static void Main()
    {
        string D="", // the whole map
            L; // initally each line of the map, later each line of output

        // TODO: some of thse might be charable
        int W=0, // width, later position
            H=0, // length (width * height)
            z; // position, later counter

        // read map and width
        for(;(L=C.ReadLine())!=null; // read a line, while we can
                H+=W=L.Length) // record the width, and increment height
            D+=L; // add the line to the map

        // disjoint sets
        int[]S=new int[H*9]; // generousness (relieve some bounds checking)
        // note that S[x] <= x, because we call R with decending values of z

        // returns whatever p points to
        int Q(int p)=>S[p]<p?Q(S[p]):p;
        // points whatever r points to at z if r is empty
        void R(int r)=>S[Q(r+=z)]=S[r]>0?z:0; // note that is never called when z=0

        // fill out disjoint sets
        for(z=H;z-->0;)
            if(D[z]<33) // if cell is empty
            {
                S[z]=z; // point it at itself

                // point the things next  to z at z
                R(1);
                R(W);
                R(W+1);
                R(W-1);
            }

        // zero sets which are against the left, bottom, or right edges
        for(;++z<H;)
            S[Q(z)]*=z>H-W-2|z%W<1|z%W>W-2?0:1; // TODO?: this suggests inverting the first loop (NOTE: would break S[x]<=x)

        // starting from the second row, count all the sets that point to this cell (ignores any non-zeros pointing to first row)
        for(;W<H;)
            z+=Q(W)<W++?0:1;

        C.WriteLine(z-H);
    }
}

それをa Func<List<string>, int>に変換して、毛羽立ちとコンソールのものを削除します。ただし、ローカル関数があるのを見たので、関数でそれらを使用できない場合があります。メソッドにコンパイルできますint h(string[] s) { }
TheLethalCoder

ここにはもっと簡単なものがもっとたくさんあると確信しています
...-TheLethalCoder

@TheLethalCoderこれを別の形式に変換するつもりはありません。関数としての回答は好きではありません(あなたが言ったように、ラムダである必要はありません)。ええ...全体が肥大化したように感じます...しかし、私はそれを変異させながらかなりの時間を費やし、実質的な進歩を遂げませんでしたので、私はいくつかのパスの「ちょっとした」ゴルフをしてそれを押しました。短いバージョンをお気軽に送信してください。私はこのバージョンに執着しています。
VisualMelon

メソッドに変換し、コンソールのすべてのものを削除するだけで、それはもはや必要ではないので、50-100バイトをノックします(推測だけですが、かなりノックします)。
TheLethalCoder

@TheLethalCoderは確かに; 関数を回答として提出するのは好きではありません。標準入力はかなり標準であり、「完全なプログラム」はどこでも簡単にコンパイルして実行できます。型付けされていないラムダで開始しないでください ...明らかに、競合するJavaの回答があった場合、標準を少し
緩める必要があり


0

JavaScript(ES6)、192バイト

v=a=>Math.min(...a=a.map(s=>s.length))==Math.max(...a);
f=(s,t=(u=` `.repeat(w=s.search`
`+1))+`
`+s.replace(/^|$/gm,` `)+`
`+u,v=t.replace(RegExp(`( |@)([^]{${w},${w+2}})?(?!\\1)[ @]`),`@$2@`))=>t!=v?f(s,v):/ /.test(t)?f(s,t.replace(` `,`@`))+1:-1
<textarea id=i rows=10 cols=10></textarea><input type=button value=Count onclick=o.textContent=/^[\s#]+$/.test(i.value)*v(i.value.split`\n`)?f(i.value):`Invalid_Entry`><span id=o>

失敗した城の検出に対する私の答えに基づいています。まず、文字列にスペースを埋めて、シェイプの周りの領域を作成します。次に、RegExpは2つの隣接する正方形を探します。1つはを含み@、もう1つはスペースを含み、両方をで置き換えます@。これができない場合は、スペースを埋めます@これを新しい穴としてカウントします。最後に、周囲の領域を説明するために1が差し引かれます。


ある種のTIOリンクを提供できますか?ありがとう!
ハイパーニュートリノ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.